pola-rs/polars · error · TypeError

'offset' must be an integer, string, or expression, not

Error message

'offset' must be an integer, string, or expression, not {type(offset).__name__}

What it means

Expr.list.slice() validates its `offset` argument: it may be an integer, a string column name, or an Expr, but not an arbitrary collection (list/tuple/dict/set). Passing a Collection raises this TypeError immediately in Python before any expression is built. Polars raises it early so the mistake surfaces at call time instead of deep in query evaluation.

Solutions

  1. Pass the offset as a single integer: list.slice(0, 2).
  2. If you intended a range [start, end], convert it: list.slice(start, end - start).
  3. If offset should come from a column, pass its name as a str or a pl.col(...) expression.

Example fix

// before
pl.col('items').list.slice([0, 3])
// after
pl.col('items').list.slice(0, 3)
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(offset, (int, str, pl.Expr)):
    raise TypeError(f'offset must be int/str/Expr, got {type(offset).__name__}')

Type guard

def is_valid_offset(v) -> bool:
    return isinstance(v, (int, str, pl.Expr))

Try / catch

try:
    expr = pl.col('a').list.slice(offset, length)
except TypeError:
    expr = pl.col('a').list.slice(int(offset[0]), length)

Prevention

When it happens

Trigger: Calling Expr.list.slice(offset, length) with offset given as a list, tuple, set, or dict (e.g. df.select(pl.col('a').list.slice([0, 2]))) instead of an int/str/Expr.

Common situations: Copy-pasting a slice range like [0, 5] as the offset; confusing Python slicing with list.slice's (offset, length) signature; programmatically building arguments and accidentally passing a list.

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


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

Appendix: source

Thrown at py-polars/src/polars/expr/list.py:1127

            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 fe841f959e)