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

GroupBy.map_groups hands each group's sub-DataFrame to a Python function via the Rust group_by_map_groups path, which identifies groups by plain column names only. Named expressions (keyword arguments like df.group_by(grp=pl.col('a') + 1)) create derived/aliased keys that this path cannot resolve back to columns, so polars raises TypeError when the GroupBy object carries any named_by entries.

Source

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

        ╞═════╪═══════╪══════════╡
        │ 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 df599052da)

Solutions

  1. Group by plain column names only: df.group_by('a').map_groups(fn)
  2. Precompute derived keys as a column first: df.with_columns((pl.col('a') % 10).alias('grp')).group_by('grp').map_groups(fn)
  3. Rename or alias the key after map_groups if a different output name is needed

Example fix

# before
out = df.group_by(grp=pl.col('a') % 10).map_groups(process_group)

# after
out = (
    df.with_columns((pl.col('a') % 10).alias('grp'))
      .group_by('grp')
      .map_groups(process_group)
)
Defensive patterns

Strategy: validation

Validate before calling

def safe_map_groups(gb, fn):
    if getattr(gb, 'named_by', None):
        raise TypeError('map_groups requires plain column-name keys; precompute derived keys as columns')
    return gb.map_groups(fn)

Prevention

When it happens

Trigger: df.group_by(grp=pl.col('a') % 10).map_groups(fn); any group_by call using keyword=Expr arguments and then chaining .map_groups(...); refactors that renamed grouping keys via kwargs for readability.

Common situations: Using named-expression syntax (fine for .agg) on pipelines that end in map_groups; deriving grouping keys on the fly (alias in the group_by) instead of precomputing a column; mixed style within a codebase.

Related errors


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