pola-rs/polars · error

cannot call `map_groups` when grouping by named expressions

Error message

cannot call `map_groups` when grouping by named expressions

What it means

`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.

Solutions

  1. 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)`.
  2. Use `map_elements`-free alternatives: compute the key with `with_columns`, then map_groups on string keys.
  3. If per-group transformation suffices, use expressions with `.over(...)` instead of map_groups.

Example fix

// before
df.group_by(pl.col('d').dt.year().alias('yr')).map_groups(fn)
// after
df.with_columns(yr=pl.col('d').dt.year()).group_by('yr').map_groups(fn)
Defensive patterns

Strategy: validation

Validate before calling

keys = ['yr']  # ensure group keys are plain strings
assert all(isinstance(k, str) for k in keys), 'map_groups requires string column keys'

Type guard

def is_named_expr(k) -> bool:
    import polars as pl
    return isinstance(k, pl.Expr) and k.meta.output_name() != k.meta.root_names()[0] if isinstance(k, pl.Expr) else False

Try / catch

try:
    out = gb.map_groups(fn)
except TypeError:
    out = df.with_columns(**{name: expr}).group_by(name).map_groups(fn)

Prevention

When it happens

Trigger: `df.group_by(pl.col('a').alias('key')).map_groups(fn)` — grouping by a named expression rather than a column string.

Common situations: Adding computed group keys (e.g. `pl.col('date').dt.year().alias('year')`) in a pipeline later switched to map_groups.

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


AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18). Data as JSON: /api/errors/03925b03ad776ec1. Report an issue: GitHub.

Appendix: source

Thrown at py-polars/src/polars/dataframe/group_by.py:444

        ╞═════╪═══════╪══════════╡
        │ 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
        ----------
        n
            Number of rows to return.

View on GitHub (pinned to fe841f959e)