pandas-dev/pandas · error · IndexError

index is out of bounds for axis 0 with size

Error message

index {key} is out of bounds for axis 0 with size {n}

What it means

In __setitem__'s integer-key fast path, after normalizing negative indices (key += n) the code checks 0 <= key < n. If the resolved index falls outside the array length, it raises IndexError with the standard numpy-style message naming axis 0 and the size. This matches ndarray.__setitem__ semantics.

Solutions

  1. Validate 0 <= key < len(arr) (or -len(arr) <= key < 0) before assignment.
  2. Resize the structure (append/reindex) instead of writing past the end.
  3. Re-derive the index after any operation that changes array length.

Example fix

// before
s = pd.Series([1, 2, 3], dtype="int64[pyarrow]")
s.iloc[5] = 99
// after
s = pd.Series([1, 2, 3], dtype="int64[pyarrow]")
if 0 <= 5 < len(s):
    s.iloc[5] = 99
Defensive patterns

Strategy: validation

Validate before calling

def safe_pos_setitem(arr, key, value):
    n = len(arr)
    if key < 0:
        key += n
    if not 0 <= key < n:
        raise IndexError(f"index {key} out of range [0,{n})")
    arr[key] = value

Type guard

def index_in_range(arr, key) -> bool:
    n = len(arr)
    k = key + n if key < 0 else key
    return 0 <= k < n

Try / catch

try:
    s.iloc[i] = v
except IndexError:
    # resize or reindex, then retry
    ...

Prevention

When it happens

Trigger: Assigning to a single position with an out-of-range integer index on a pyarrow-backed Series/array, e.g. s.iloc[10] = x where len(s) <= 10.

Common situations: Loop indices computed without bounds check; off-by-one after filtering; assigning into an array sized against stale metadata.

Related errors


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

Appendix: source

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

        if com.is_null_slice(key):
            # fast path (GH50248)
            if (
                isinstance(value, (pa.Array, pa.ChunkedArray))
                and value.type == self._pa_array.type
                and len(value) == len(self)
            ):
                data = value
            else:
                data = self._if_else(True, value, self._pa_array)

        elif is_integer(key):
            # fast path
            key = cast("int", key)
            n = len(self)
            if key < 0:
                key += n
            if not 0 <= key < n:
                raise IndexError(
                    f"index {key} is out of bounds for axis 0 with size {n}"
                )
            if isinstance(value, pa.Scalar):
                value = value.as_py()
            elif is_list_like(value):
                raise ValueError("Length of indexer and values mismatch")
            chunks = [
                *self._pa_array[:key].chunks,
                pa.array([value], type=self._pa_array.type, from_pandas=is_nan_na()),
                *self._pa_array[key + 1 :].chunks,
            ]
            data = pa.chunked_array(chunks).combine_chunks()

        elif is_bool_dtype(key):
            key = np.asarray(key, dtype=np.bool_)
            data = self._replace_with_mask(self._pa_array, key, value)

        elif is_scalar(value) or isinstance(value, pa.Scalar):

View on GitHub (pinned to 3b7651241d)