pola-rs/polars · error
cannot call `map_groups` when filtering groups with `having`
Error message
cannot call `map_groups` when filtering groups with `having`
What it means
GroupBy.map_groups applies an arbitrary Python function to each group's sub-DataFrame via the Rust group_by_map_groups path. When the GroupBy object carries `having` predicates (set by the GroupBy.having() post-aggregation filter API), map_groups cannot honor them — its execution path has no notion of the filter — so polars raises TypeError rather than silently ignoring the filter.
Source
Thrown at py-polars/src/polars/dataframe/group_by.py:447
│ id ┆ color ┆ shape │
│ --- ┆ --- ┆ --- │
│ i64 ┆ str ┆ str │
╞═════╪═══════╪══════════╡
│ 1 ┆ green ┆ triangle │
│ 2 ┆ green ┆ square │
│ 4 ┆ red ┆ square │
│ 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
----------View on GitHub (pinned to df599052da)
Solutions
- Keep having() with expression aggregations: df.group_by('a').agg(pl.col('b').sum()).having(pl.col('b') > 10) — do not use map_groups on the filtered GroupBy
- If map_groups is required, drop having() and filter inside the function (it receives each group frame) or filter the map_groups result afterwards
- Rewrite as window expressions with over(...) and filter the frame, as the map_groups docstring recommends
Example fix
# before
out = df.group_by('color').having(pl.len() > 2).map_groups(lambda g: g.sorted('size').head(1))
# after
out = (
df.group_by('color')
.map_groups(lambda g: g.sorted('size').head(1))
)
out = out.filter(pl.count().over('color') > 2) Defensive patterns
Strategy: validation
Validate before calling
def safe_map_groups(gb, fn):
if getattr(gb, 'predicates', None):
raise TypeError('do not combine having() with map_groups; filter after aggregation instead')
return gb.map_groups(fn) Prevention
- Keep SQL HAVING semantics in the declarative API: group_by().agg() plus having()/filter
- Treat having() and map_groups as mutually exclusive when writing group pipelines
- For group filtering with custom functions, filter inside fn or filter the map_groups output
When it happens
Trigger: df.group_by('a').having(pl.col('b').sum() > 10).map_groups(fn); chaining .having(...) onto an existing group_by pipeline that ends in map_groups; the same pattern on RollingGroupBy/DynamicGroupBy map_groups variants.
Common situations: Porting SQL HAVING clauses onto polars using the fluent having() API; adding group filters to legacy map_groups code during a polars upgrade that introduced having(); mixed declarative/imperative group pipelines.
Related errors
- cannot call `map_groups` when grouping by named expressions
- Expected Polars expression or object convertible to one, got
- cannot select columns using key of type {qualified_type_name
- cannot select rows using key of type {qualified_type_name(ke
- cannot treat Series of type {s.dtype} as indices
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/74834632fb67de94.
Report an issue: GitHub.