pola-rs/polars · error

Expected Polars expression or object convertible to one, got

Error message

Expected Polars expression or object convertible to one, got {type(value)}.

Hint: if you tried
    group_by(by={value!r})
then you probably want to use this instead:
    group_by({value!r})

What it means

DataFrame.group_by(*by, **named_by) accepts positional grouping keys plus keyword 'named' expressions. Every value reaching it — positional or keyword — must be a str, pl.Expr, or pl.Series; anything else raises TypeError. The most common cause is df.group_by(by={...}) or df.group_by(by=[...]): `by` is not a named parameter of this method, so Python captures it into **named_by, and the error embeds a Hint showing the exact rewrite for that case.

Source

Thrown at py-polars/src/polars/dataframe/frame.py:7313

        shape: (1, 3)
        ┌─────┬─────┬─────┐
        │ a   ┆ b   ┆ c   │
        │ --- ┆ --- ┆ --- │
        │ str ┆ i64 ┆ i64 │
        ╞═════╪═════╪═════╡
        │ c   ┆ 3   ┆ 1   │
        └─────┴─────┴─────┘
        """
        for value in named_by.values():
            if not isinstance(value, (str, pl.Expr, pl.Series)):
                msg = (
                    f"Expected Polars expression or object convertible to one, got {type(value)}.\n\n"
                    "Hint: if you tried\n"
                    f"    group_by(by={value!r})\n"
                    "then you probably want to use this instead:\n"
                    f"    group_by({value!r})"
                )
                raise TypeError(msg)
        return GroupBy(
            self, *by, **named_by, maintain_order=maintain_order, predicates=None
        )

    @deprecate_renamed_parameter("by", "group_by", version="0.20.14")
    def rolling(
        self,
        index_column: IntoExpr,
        *,
        period: str | timedelta,
        offset: str | timedelta | None = None,
        closed: ClosedInterval = "right",
        group_by: IntoExpr | Iterable[IntoExpr] | None = None,
    ) -> RollingGroupBy:
        """
        Create rolling groups based on a temporal or integer column.

        Different from a `group_by_dynamic` the windows are now determined by the

View on GitHub (pinned to df599052da)

Solutions

  1. Pass grouping keys positionally or as one iterable: df.group_by('a', 'b') or df.group_by(['a', 'b'])
  2. For a named expression use a keyword with an Expr value: df.group_by(dept=pl.col('department'))
  3. Convert foreign objects first (numpy array -> pl.Series) or reference the column by name instead of passing raw data
  4. Read the Hint in the message — it states verbatim: use group_by(<your value>) instead of group_by(by=<your value>)

Example fix

# before
result = df.group_by(by=['a', 'b']).agg(pl.len())

# after
result = df.group_by(['a', 'b']).agg(pl.len())  # or df.group_by('a', 'b')
Defensive patterns

Strategy: type-guard

Validate before calling

from polars.expr import Expr
from polars.series import Series

for v in list(by) + list(named_by.values()):
    if not isinstance(v, (str, Expr, Series)):
        raise TypeError(f'group_by key must be str/Expr/Series, got {type(v)!r}')

Type guard

from polars.expr import Expr
from polars.series import Series

def is_group_by_key(v: object) -> bool:
    return isinstance(v, (str, Expr, Series))

Try / catch

try:
    gb = df.group_by(*by, **named)
except TypeError as e:
    if 'group_by' not in str(e):
        raise
    # follow the embedded Hint: pass the value positionally
    gb = df.group_by(list(by) + list(named.values()))

Prevention

When it happens

Trigger: df.group_by(by=['a', 'b']) or df.group_by(by={'a': 1}) (the by= keyword lands in named_by as a list/dict); df.group_by(grp=<numpy array or pandas object>) passing a non-polars object as a named key.

Common situations: Translating pandas df.groupby(by=...) to polars; assuming group_by accepts keyword containers like join/pivot do; IDE autocompletion inserting by=; forwarding kwargs from a generic wrapper into group_by.

Related errors


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