pola-rs/polars · error
cannot call `map_groups` when grouping by an expression
Error message
cannot call `map_groups` when grouping by an expression
What it means
`map_groups` passes group keys directly to the Rust `group_by_map_groups`; only column-name strings are supported. This TypeError fires when any group key is a non-string expression (e.g. `pl.col('a')`) rather than a literal column name.
Solutions
- Replace expressions with the column name string: `group_by('a').map_groups(fn)`.
- For computed keys, materialize them with `with_columns` first, then group by the new column name.
- Use `.over(key_expr)` expression APIs if a plain transformation (not arbitrary Python fn) is needed.
Example fix
// before
df.group_by(pl.col('region')).map_groups(fn)
// after
df.group_by('region').map_groups(fn) Defensive patterns
Strategy: type-guard
Validate before calling
import polars as pl keys = ['region'] assert all(isinstance(k, str) for k in keys), 'group keys for map_groups must be strings'
Type guard
def are_column_names(keys) -> bool:
return all(isinstance(k, str) for k in keys) Try / catch
try:
out = gb.map_groups(fn)
except TypeError:
names = [e.meta.output_name() for e in key_exprs]
out = df.group_by(names).map_groups(fn) Prevention
- Always pass column-name strings to group_by before map_groups
- Convert pl.col('x') to 'x' at call sites
- Use .over() for expression-based grouping needs
When it happens
Trigger: `df.group_by(pl.col('a')).map_groups(fn)` or grouping by a tuple/list containing expressions.
Common situations: Reusing an expression-based group_by written for aggregations; dynamic group keys built programmatically as expressions.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- cannot call `map_groups` when filtering groups with `having`
- cannot call `map_groups` when grouping by named expressions
- arr.to_struct() got a str instead of a list. hint: pass
- cannot set Series of dtype
- cannot use " " for indexing
AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18).
Data as JSON: /api/errors/e4c30c6e727f05d0.
Report an issue: GitHub.
Appendix: source
Thrown at py-polars/src/polars/dataframe/group_by.py:448
│ 3 ┆ red ┆ triangle │
└─────┴───────┴──────────┘
It is better to implement this with an expression:
>>> df.filter(
... pl.int_range(pl.len()).shuffle().over("color") < 2
... ) # doctest: +IGNORE_RESULT
"""
if self.predicates:
msg = "cannot call `map_groups` when filtering groups with `having`"
raise TypeError(msg)
if self.named_by:
msg = "cannot call `map_groups` when grouping by named expressions"
raise TypeError(msg)
by = list(_parse_inputs_as_iterable(self.by))
if not all(isinstance(c, str) for c in by):
msg = "cannot call `map_groups` when grouping by an expression"
raise TypeError(msg)
return self.df.__class__._from_pydf(
self.df._df.group_by_map_groups(by, function, self.maintain_order)
)
def head(self, n: int = 5) -> DataFrame:
"""
Get the first `n` rows of each group.
Parameters
----------
n
Number of rows to return.
Examples
--------
>>> df = pl.DataFrame(
... {View on GitHub (pinned to fe841f959e)