{"record":{"id":"03925b03ad776ec1","repo":"pola-rs/polars","slug":"cannot-call-map-groups-when-grouping-by-named-ex","errorCode":null,"errorMessage":"cannot call `map_groups` when grouping by named expressions","messagePattern":"cannot call `map_groups` when grouping by named expressions","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/dataframe/group_by.py","lineNumber":444,"sourceCode":"        ╞═════╪═══════╪══════════╡\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        ----------\n        n\n            Number of rows to return.\n","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/pola-rs/polars/blob/fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e/py-polars/src/polars/dataframe/group_by.py#L426-L462","documentation":"`map_groups` requires group keys as plain column-name strings because they are passed to the Rust backend. When `group_by` was called with named expressions (e.g. `group_by(pl.col('a').alias('x'))`), map_groups refuses to run.","triggerScenarios":"`df.group_by(pl.col('a').alias('key')).map_groups(fn)` — grouping by a named expression rather than a column string.","commonSituations":"Adding computed group keys (e.g. `pl.col('date').dt.year().alias('year')`) in a pipeline later switched to map_groups.","solutions":["Group by plain column name strings: add the computed key as a column first (`df.with_columns(year=pl.col('date').dt.year())`) then `group_by('year').map_groups(fn)`.","Use `map_elements`-free alternatives: compute the key with `with_columns`, then map_groups on string keys.","If per-group transformation suffices, use expressions with `.over(...)` instead of map_groups."],"exampleFix":"// before\ndf.group_by(pl.col('d').dt.year().alias('yr')).map_groups(fn)\n// after\ndf.with_columns(yr=pl.col('d').dt.year()).group_by('yr').map_groups(fn)","handlingStrategy":"validation","validationCode":"keys = ['yr']  # ensure group keys are plain strings\nassert all(isinstance(k, str) for k in keys), 'map_groups requires string column keys'","typeGuard":"def is_named_expr(k) -> bool:\n    import polars as pl\n    return isinstance(k, pl.Expr) and k.meta.output_name() != k.meta.root_names()[0] if isinstance(k, pl.Expr) else False","tryCatchPattern":"try:\n    out = gb.map_groups(fn)\nexcept TypeError:\n    out = df.with_columns(**{name: expr}).group_by(name).map_groups(fn)","preventionTips":["Group by string column names when using map_groups","Materialize derived keys with with_columns first","Prefer expression .over() APIs over map_groups where possible"],"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"}