pandas-dev/pandas · error · ValueError

key must be an int or slice, got

Error message

key must be an int or slice, got {type(key).__name__}

What it means

`ValueError('key must be an int or slice, got {type}')` from `ListAccessor.__getitem__`. The accessor only accepts an `int` (positional list index, forwarded to `pc.list_element`) or a `slice` (forwarded to `pc.list_slice`). Anything else — a string field name, a list of indices, a numpy array, a tuple — falls through to the `else` and raises. Note negative int is not yet supported (pyarrow limitation called out in the code).

Solutions

  1. Use an int for a single position: `s.list[0]`.
  2. Use a slice for a sub-range: `s.list[0:2]`.
  3. For per-row variable indices, build an integer pyarrow array and use `pc.list_element` directly, or `explode`+filter.
  4. If you meant a named field, switch to `.struct.field(name)` on a struct-dtype Series.

Example fix

// before
s.list[[0, 1]]            # list key -> ValueError
s.list['first']           # str key -> ValueError

// after
s.list[0:2]               # slice
# per-row indices:
idx = pa.array([0,1,0])
pd.Series(pa.compute.list_element(s.array._pa_array, idx), index=s.index)
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(key, (int, slice)):
    raise TypeError(f'list accessor key must be int or slice, got {type(key).__name__}')
s.list[key]

Type guard

def is_valid_list_key(key) -> bool:
    return isinstance(key, (int, slice)) and not (isinstance(key, int) and key < 0)

Try / catch

try:
    out = s.list[key]
except ValueError as e:
    if 'key must be an int or slice' in str(e):
        raise TypeError('Use .list[int] or .list[slice]; for names use .struct.field') from e
    raise

Prevention

When it happens

Trigger: `s.list['name']` (string), `s.list[[0,1]]` (list), `s.list[1:3:2]` works but `s.list[-1]` is unsupported, `s.list[arr]` (numpy array), `s.list[(0,1)]` (tuple).

Common situations: Confusing the list accessor with the struct accessor (`.list` indexes positions, `.struct.field` indexes names); trying fancy indexing; assuming negative indexing works as it does on Python lists.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/393610b54f743394. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/arrays/arrow/accessors.py:195

            # TODO: Support negative start/stop/step, ideally this would be added
            # upstream in pyarrow.
            start, stop, step = key.start, key.stop, key.step
            if start is None:
                # TODO: When adding negative step support
                #  this should be set to last element of array
                # when step is negative.
                start = 0
            if step is None:
                step = 1
            sliced = pc.list_slice(self._pa_array, start, stop, step)
            return Series(
                sliced,
                dtype=ArrowDtype(sliced.type),
                index=self._data.index,
                name=self._data.name,
            )
        else:
            raise ValueError(f"key must be an int or slice, got {type(key).__name__}")

    def __iter__(self) -> Iterator:
        raise TypeError(f"'{type(self).__name__}' object is not iterable")

    def flatten(self) -> Series:
        """
        Flatten list values.

        Each list element is expanded into separate rows, preserving the
        original index. The resulting Series may have a longer length than
        the original if lists contain more than one element.

        Returns
        -------
        pandas.Series
            The data from all lists in the series flattened.

        See Also

View on GitHub (pinned to 3b7651241d)