pandas-dev/pandas · error · IndexError

only integers, slices (`:`), ellipsis (`...`), numpy.newaxis

Error message

only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices

What it means

Raised by ArrowExtensionArray.__getitem__ when the indexer is scalar but not an integer (e.g. a string label, a float like 2.5). The guard at line 905 explicitly checks `is_scalar(item) and not is_integer(item)` and raises with a numpy-style message. Positional indexing on ArrowExtensionArray requires integer positions; label-based access must go through .loc.

Source

Thrown at pandas/core/arrays/arrow/array.py:908

                return self.take(item)
            elif item.dtype.kind == "b":
                return self._from_pyarrow_array(self._pa_array.filter(item))
            else:
                raise IndexError(
                    "Only integers, slices and integer or "
                    "boolean arrays are valid indices."
                )
        elif isinstance(item, tuple):
            item = unpack_tuple_and_ellipses(item)

        if item is Ellipsis:
            # TODO: should be handled by pyarrow?
            item = slice(None)

        if is_scalar(item) and not is_integer(item):
            # e.g. "foo" or 2.5
            # exception message copied from numpy
            raise IndexError(
                r"only integers, slices (`:`), ellipsis (`...`), numpy.newaxis "
                r"(`None`) and integer or boolean arrays are valid indices"
            )
        # We are not an array indexer, so maybe e.g. a slice or integer
        # indexer. We dispatch to pyarrow.
        value = self._pa_array[item]
        if isinstance(value, pa.ChunkedArray):
            result = self._from_pyarrow_array(value)
            if getitem_returns_view(self, item):
                result._readonly = self._readonly
            return result
        else:
            pa_type = self._pa_array.type
            scalar = value.as_py()
            if scalar is None:
                return self._dtype.na_value
            elif pa.types.is_timestamp(pa_type) and pa_type.unit != "ns":
                # GH 53326

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Use an explicit int: s_arr[int(idx)].
  2. For label access go through the Series: series.loc['a'].
  3. Validate indices: int_idx = operator.index(idx) before indexing.
  4. If idx is a numpy scalar, cast: s_arr[int(idx.item())].

Example fix

# before
val = arrow_arr['field_a']   # IndexError: scalar non-int
val = arrow_arr[2.0]         # IndexError
# after
val = series.loc['field_a']  # label access
val = arrow_arr[int(2.0)]    # positional int
Defensive patterns

Strategy: validation

Validate before calling

import operator

def safe_scalar_get(arr, item):
    if isinstance(item, str):
        raise IndexError('use Series.loc for label access')
    try:
        item = operator.index(item)
    except TypeError as e:
        raise IndexError(f'non-integer scalar index {item!r}') from e
    return arr[item]

val = safe_scalar_get(arrow_arr, idx)

Type guard

import numbers

def is_integer_scalar_index(x) -> bool:
    return isinstance(x, numbers.Integral) and not isinstance(x, bool)

Try / catch

try:
    val = arrow_arr[key]
except IndexError as e:
    if 'only integers' in str(e):
        # route label access through Series
        val = pd.Series(arrow_arr).loc[key]
    else:
        raise

Prevention

When it happens

Trigger: Indexing positionally with a label: `s_arr['a']` on an ArrowExtensionArray, or `s_arr[2.0]`. Floating scalar indices. Also passing an Ellipsis-wrapped tuple that collapses to a non-int scalar.

Common situations: Treating an ExtensionArray like a Series (which supports label indexing), or assuming integer-valued floats round. Common when migrating numpy-backed code where `arr[2.0]` silently truncated to `arr[2]`.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/55f69b74812de448. Report an issue: GitHub.