I believe this is (kind of) documented behaviour. While you can use grouped input frame and columns with dplyr::count() to add another grouping layer, it's either groups or columns for {tidytable} implementation:
count() returns counts by group on a grouped tidytable, or column names can be specified to return counts by group. ( Count observations by group — count • tidytable )
Meaning that when used with a grouped frame (object with class grouped_tt), columns passed to tidytable::count() are just discarded and never evaluated. You can check tidytable:::count.grouped_tt or pass some non-existing columns to count() and check that it never throws an error or warning:
dplyr::starwars |>
tidytable::group_by(sex) |>
tidytable::count(foobar)
#> # A tidytable: 5 × 2
#> # Groups: sex
#> sex n
#> <chr> <int>
#> 1 <NA> 4
#> 2 female 16
#> 3 hermaphroditic 1
#> 4 male 60
#> 5 none 6
I can't say that your example is an anti-pattern, but it's definitely more common to let count() do all the grouping or none at all, and for the latter case many actually use tally() instead. All three cases work the same with both {dplyr} and {tidytable} :
dplyr::starwars |>
tidytable::count(sex, gender)
#> # A tidytable: 6 × 3
#> sex gender n
#> <chr> <chr> <int>
#> 1 <NA> <NA> 4
#> 2 female feminine 16
#> 3 hermaphroditic masculine 1
#> 4 male masculine 60
#> 5 none feminine 1
#> 6 none masculine 5
dplyr::starwars |>
tidytable::group_by(sex, gender) |>
tidytable::count()
#> # A tidytable: 6 × 3
#> # Groups: sex, gender
#> sex gender n
#> <chr> <chr> <int>
#> 1 <NA> <NA> 4
#> 2 female feminine 16
#> 3 hermaphroditic masculine 1
#> 4 male masculine 60
#> 5 none feminine 1
#> 6 none masculine 5
dplyr::starwars |>
tidytable::group_by(sex, gender) |>
tidytable::tally()
#> # A tidytable: 6 × 3
#> # Groups: sex
#> sex gender n
#> <chr> <chr> <int>
#> 1 <NA> <NA> 4
#> 2 female feminine 16
#> 3 hermaphroditic masculine 1
#> 4 male masculine 60
#> 5 none feminine 1
#> 6 none masculine 5
If you do need to pass grouped frames and a set of columns to count(), perhaps try {dtplyr}. It comes with less translated verbs but as it uses lazy evaluation and translates whole pipeline for data.table in one go, not eagerly like {tidytable}, there can be few such coroner cases where it behaves more like {dplyr}:
library(dtplyr)
library(dplyr, warn.conflicts = FALSE)
starwars |>
lazy_dt() |>
group_by(sex) |>
count(gender)
#> Source: local data table [6 x 3]
#> Call: `_DT1`[, .(n = .N), keyby = .(sex, gender)]
#>
#> sex gender n
#> <chr> <chr> <int>
#> 1 <NA> <NA> 4
#> 2 female feminine 16
#> 3 hermaphroditic masculine 1
#> 4 male masculine 60
#> 5 none feminine 1
#> 6 none masculine 5
#>
#> # Use as.data.table()/as.data.frame()/as_tibble() to access results
Created on 2025-10-04 with reprex v2.1.1