pola-rs/polars · error · TypeError
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
LazyFrame.group_by() only accepts Polars expressions or objects directly convertible to one (column names as strings, lists of them). This error is thrown when an unconvertible object (e.g. a list literal, dict, Series misuse, or Python value) is passed to `by`. The hint suggests the common mistake of wrapping the column name in a keyword call, e.g. group_by(by='a') instead of group_by('a').
Solutions
- Pass column names as positional strings or a list of strings: group_by('a') or group_by(['a','b'])
- Use pl.col('a') expressions instead of raw Python objects
- If you used the `by=` keyword with a string/list of strings, drop the keyword and pass positionally
- Convert foreign containers (pandas Series, numpy arrays) to Python lists or pl.Series first
Example fix
// before
df.lazy().group_by(by=['a', 'b']).agg(pl.col('x').sum())
// after
df.lazy().group_by(['a', 'b']).agg(pl.col('x').sum()) Defensive patterns
Strategy: type-guard
Validate before calling
def valid_group_keys(by):
if isinstance(by, str):
return True
if isinstance(by, list):
return all(isinstance(x, (str, pl.Expr)) for x in by)
return isinstance(by, pl.Expr)
# call: lf.group_by(by) only if valid_group_keys(by) Type guard
def is_polars_key(v) -> bool:
return isinstance(v, (str, pl.Expr)) or (isinstance(v, list) and all(isinstance(x, (str, pl.Expr)) for x in v)) Try / catch
try:
out = lf.group_by(keys).agg(...)
except TypeError as e:
if 'Expected Polars expression' in str(e):
keys = keys if isinstance(keys, list) else [keys]
keys = [k if isinstance(k, (str, pl.Expr)) else str(k) for k in keys]
out = lf.group_by(keys).agg(...) Prevention
- Pass group keys positionally as strings or pl.col expressions
- Never wrap the column name in by= keyword form
- Convert pandas Series/numpy arrays to Python lists before grouping
- Add a unit test covering each dynamic key source
When it happens
Trigger: Calling df.lazy().group_by(by=<non-expression>) where `by` is not a str, pl.Expr, or list of those — e.g. passing a Python list value, a dict, a Series used as `by=<series>` in keyword position, or writing group_by(by='col') with a string in the `by` keyword where parse_into_list_of_expressions rejects it.
Common situations: Migrating from pandas groupby where a list/Series is passed; writing group_by(by=['a','b']) after seeing the signature has a `by` parameter; confusing positional/named argument usage; passing a pandas Series or numpy array directly.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- `arctan2` expected a `str` or `Expr` got a
- `arctan2` expected a `str` or `Expr` got a
- cannot convert Python type
- expected Series in 'arg_where' if 'eager=True', got
- `map` with `returns_scalar=False` must return a Series…
AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18).
Data as JSON: /api/errors/20c20d0c923c9c75.
Report an issue: GitHub.
Appendix: source
Thrown at py-polars/src/polars/lazyframe/frame.py:5053
│ a ┆ b ┆ c │
│ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ f64 │
╞═════╪═════╪═════╡
│ a ┆ 0 ┆ 4.0 │
│ b ┆ 1 ┆ 3.0 │
│ c ┆ 1 ┆ 1.0 │
└─────┴─────┴─────┘
"""
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)
exprs = parse_into_list_of_expressions(*by, **named_by)
lgb = self._ldf.group_by(exprs, maintain_order)
return LazyGroupBy(lgb)
@removed_parameters(
RenamedParameter(
name="by",
new_name="group_by",
deprecated_in="0.20.14",
removed_in="2.0",
)
)
def rolling(
self,
index_column: IntoExpr,
*,
period: str | timedelta,
offset: str | timedelta | None = None,View on GitHub (pinned to fe841f959e)