pola-rs/polars · error

invalid index value: {idx!r}

Error message

invalid index value: {idx!r}

What it means

Thrown by cs.by_index (py-polars/src/polars/selectors.py:1202) when an argument is neither an int, a range, nor a Sequence. by_index flattens ints, ranges, and sequences of ints into one index list; any other object (a string like "0", a float like 1.5, a numpy scalar that is not a Python int) fails with TypeError.

Source

Thrown at py-polars/src/polars/selectors.py:1202

    >>> df.select(~cs.by_index(range(1, 100, 2)))
    shape: (1, 51)
    ┌─────┬─────┬─────┬─────┬───┬──────┬──────┬──────┬──────┐
    │ key ┆ c01 ┆ c03 ┆ c05 ┆ … ┆ c93  ┆ c95  ┆ c97  ┆ c99  │
    │ --- ┆ --- ┆ --- ┆ --- ┆   ┆ ---  ┆ ---  ┆ ---  ┆ ---  │
    │ str ┆ f64 ┆ f64 ┆ f64 ┆   ┆ f64  ┆ f64  ┆ f64  ┆ f64  │
    ╞═════╪═════╪═════╪═════╪═══╪══════╪══════╪══════╪══════╡
    │ abc ┆ 0.5 ┆ 1.5 ┆ 2.5 ┆ … ┆ 46.5 ┆ 47.5 ┆ 48.5 ┆ 49.5 │
    └─────┴─────┴─────┴─────┴───┴──────┴──────┴──────┴──────┘
    """
    all_indices: builtins.list[int] = []
    for idx in indices:
        if isinstance(idx, (range, Sequence)):
            all_indices.extend(idx)  # type: ignore[arg-type]
        elif isinstance(idx, int):
            all_indices.append(idx)
        else:
            msg = f"invalid index value: {idx!r}"
            raise TypeError(msg)

    return Selector._from_pyselector(PySelector.by_index(all_indices, require_all))


def by_name(*names: str | Collection[str], require_all: bool = True) -> Selector:
    """
    Select all columns matching the given names.

    .. versionadded:: 0.20.27
      The `require_all` parameter was added.

    Parameters
    ----------
    *names
        One or more names of columns to select.
    require_all
        Whether to match *all* names (the default) or *any* of the names.

View on GitHub (pinned to df599052da)

Solutions

  1. Pass ints, ranges, or sequences of ints: cs.by_index(0), cs.by_index(range(3)), cs.by_index([0, 1, 2])
  2. Convert parsed values: cs.by_index(int(arg)) or cs.by_index([int(i) for i in arg.split(",")])
  3. For numpy float results use cs.by_index(np.where(cond)[0].astype(int))

Example fix

# before
cols = df.select(cs.by_index("0"))  # str index from CLI/JSON

# after
cols = df.select(cs.by_index(int("0")))
# or
cols = df.select(cs.by_index([int(i) for i in ["0", "1"]]))
Defensive patterns

Strategy: validation

Validate before calling

from polars import selectors as cs

idx = [int(i) for i in "0,2,5".split(",")]  # strings from CLI/JSON
sel = cs.by_index(idx)

Type guard

from collections.abc import Sequence
from typing import TypeGuard

def is_index_arg(x: object) -> TypeGuard[int | range | Sequence[int | range]]:
    return isinstance(x, (int, range, Sequence))

Try / catch

try:
    sel = cs.by_index(*raw)
except TypeError as e:
    if "invalid index value" in str(e):
        raw = [int(x) if isinstance(x, str) else x for x in raw]
        sel = cs.by_index(*raw)
    else:
        raise

Prevention

When it happens

Trigger: cs.by_index("0"), cs.by_index(1.5), cs.by_index(np.int64(0)) is fine (int subclass), but cs.by_index("0,1,2") or cs.by_index([0, 1.5]) fail — 1.5 inside a list is not an int and is appended unchecked via extend, but a float top-level arg raises here.

Common situations: Indices parsed from CLI args or JSON are strings; numpy float indices from np.where(...)[0] style code that yields floats; hardcoding a float by mistake.

Related errors


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