pola-rs/polars · error · TypeError
'offset' must be an integer, string, or expression, not {typ
Error message
'offset' must be an integer, string, or expression, not {type(offset).__name__} What it means
Expr.list.slice validates `offset` before parsing it into an expression: it must be an int, a column name (str), or an Expr — anything that is a collections.abc.Collection (except str), such as a list, tuple, set, or dict, raises TypeError with the offending type name. The rejection exists because a bare collection is almost always a mistake (e.g. passing a list of per-row offsets that was never wrapped as a Series/Expr) and parse_into_expression would otherwise misinterpret it.
Source
Thrown at py-polars/src/polars/expr/list.py:1132
end of the list.
Examples
--------
>>> df = pl.DataFrame({"a": [[1, 2, 3, 4], [10, 2, 1]]})
>>> df.with_columns(slice=pl.col("a").list.slice(1, 2))
shape: (2, 2)
┌─────────────┬───────────┐
│ a ┆ slice │
│ --- ┆ --- │
│ list[i64] ┆ list[i64] │
╞═════════════╪═══════════╡
│ [1, 2, … 4] ┆ [2, 3] │
│ [10, 2, 1] ┆ [2, 1] │
└─────────────┴───────────┘
"""
if isinstance(offset, Collection) and not isinstance(offset, str):
msg = f"'offset' must be an integer, string, or expression, not {type(offset).__name__}"
raise TypeError(msg)
if (
length is not None
and isinstance(length, Collection)
and not isinstance(length, str)
):
msg = f"'length' must be an integer, string, or expression, not {type(length).__name__}"
raise TypeError(msg)
offset_pyexpr = parse_into_expression(offset)
length_pyexpr = parse_into_expression(length)
return wrap_expr(self._pyexpr.list_slice(offset_pyexpr, length_pyexpr))
def head(self, n: int | str | Expr = 5) -> Expr:
"""
Slice the first `n` values of every sub-list.
.. engine-support:: in-memory, streaming, distributed
View on GitHub (pinned to df599052da)
Solutions
- For a constant offset pass an int: list.slice(1).
- For per-row offsets, put them in a column and pass an expression: list.slice(pl.col('offs')) or the column name as str.
- In generic wrappers, convert Sequences with pl.Series(offset) inside pl.lit(...) or select-based expressions before forwarding.
Example fix
# before
pl.col('l').list.slice(offset=[1, 2])
# after
pl.col('l').list.slice(offset=1)
# per-row offsets:
df.with_columns(pl.col('l').list.slice(pl.col('offs'))) Defensive patterns
Strategy: type-guard
Validate before calling
from collections.abc import Collection
if isinstance(offset, Collection) and not isinstance(offset, str):
raise TypeError(f'offset must be int/str/Expr, got {type(offset).__name__}') Type guard
from collections.abc import Collection
def is_valid_slice_arg(v) -> bool:
return v is None or isinstance(v, (int, str)) or hasattr(v, '_pyexpr') Prevention
- list.slice takes int | str | Expr — wrap Python sequences in a column first.
- Never forward untyped Sequence parameters from public APIs into polars expression arguments.
When it happens
Trigger: pl.col('l').list.slice([1, 2]) or list.slice(offset=(1,)) — passing a Python list/tuple where an int or expression is expected; also np arrays if registered as collections.
Common situations: Wanting per-row offsets: developers have a Python list of offsets (one per row) and pass it directly instead of a column; API wrappers that accept Sequence[int] and forward it unchanged; confusing slice semantics with Python's list slicing that accepts tuples.
Related errors
- 'length' must be an integer, string, or expression, not {typ
- cannot specify both `n` and `fraction`
- cannot turn {qualified_type_name(input)!r} into selector
- Cannot pass a dictionary as a single positional argument.\nI
- expressions should be passed to the `by_predicate` parameter
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/7da9d3e67fa75f1c.
Report an issue: GitHub.