{"record":{"id":"74834632fb67de94","repo":"pola-rs/polars","slug":"cannot-call-map-groups-when-filtering-groups-wit","errorCode":null,"errorMessage":"cannot call `map_groups` when filtering groups with `having`","messagePattern":"cannot call `map_groups` when filtering groups with `having`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/dataframe/group_by.py","lineNumber":441,"sourceCode":"        │ id  ┆ color ┆ shape    │\n        │ --- ┆ ---   ┆ ---      │\n        │ i64 ┆ str   ┆ str      │\n        ╞═════╪═══════╪══════════╡\n        │ 1   ┆ green ┆ triangle │\n        │ 2   ┆ green ┆ square   │\n        │ 4   ┆ red   ┆ square   │\n        │ 3   ┆ red   ┆ triangle │\n        └─────┴───────┴──────────┘\n\n        It is better to implement this with an expression:\n\n        >>> df.filter(\n        ...     pl.int_range(pl.len()).shuffle().over(\"color\") < 2\n        ... )  # doctest: +IGNORE_RESULT\n        \"\"\"\n        if self.predicates:\n            msg = \"cannot call `map_groups` when filtering groups with `having`\"\n            raise TypeError(msg)\n        if self.named_by:\n            msg = \"cannot call `map_groups` when grouping by named expressions\"\n            raise TypeError(msg)\n        by = list(_parse_inputs_as_iterable(self.by))\n        if not all(isinstance(c, str) for c in by):\n            msg = \"cannot call `map_groups` when grouping by an expression\"\n            raise TypeError(msg)\n\n        return self.df.__class__._from_pydf(\n            self.df._df.group_by_map_groups(by, function, self.maintain_order)\n        )\n\n    def head(self, n: int = 5) -> DataFrame:\n        \"\"\"\n        Get the first `n` rows of each group.\n\n        Parameters\n        ----------","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/pola-rs/polars/blob/fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e/py-polars/src/polars/dataframe/group_by.py#L423-L459","documentation":"`df.group_by(...).map_groups(...)` applies a Python function per group. Polars rejects this when the GroupBy also carries `having` predicates (filtering groups), because group-level filtering combined with arbitrary map_groups output has no well-defined result.","triggerScenarios":"Calling `.group_by(cols).having(pl.col('x') > 1).map_groups(fn)` — i.e. any map_groups after a `having` filter.","commonSituations":"Building a query fluently where having-filtering was added for an aggregate step and then reused for map_groups; porting SQL HAVING logic onto a map_groups pipeline.","solutions":["Apply the group filter before/without having: compute groups with map_groups first, then `filter` the resulting DataFrame.","Use `filter` over a window function instead of `having`: `df.filter(cond.over(group_cols))` then group_by/map_groups.","Split into two steps: aggregate with having, then map_groups on the filtered frame.","Restructure the function so filtering happens inside the per-group function."],"exampleFix":"// before\ndf.group_by('g').having(pl.len() > 2).map_groups(fn)\n// after\ndf.group_by('g').map_groups(fn).filter(pl.len() > 2)  # or filter groups pre-hoc","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    out = gb.map_groups(fn)\nexcept TypeError as e:\n    if 'having' in str(e):\n        out = df.filter(cond.over(group_cols)).group_by(group_cols).map_groups(fn)","preventionTips":["Do not combine having() with map_groups in the same GroupBy","Filter groups with window functions (cond.over(...)) before group_by","Keep having for pure aggregations only"],"tags":["python","polars","group-by","type-error"],"backgroundTag":"unsupported-operation","analyzedSha":"fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e","analyzedAt":"2026-09-18T22:14:11.667Z","contentChangedAt":"2026-09-18T22:14:11.667Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}