pandas-dev/pandas · error · IndexError
index is out of bounds: must be an integer between -{n} and
Error message
index is out of bounds: must be an integer between -{n} and {n - 1} What it means
Raised by SparseArray._get_val_at when the requested integer position loc is outside [-n, n-1] after negative-index normalization. It mirrors numpy IndexError semantics but is emitted from the sparse lookup path so the caller learns the valid bounds before the sp_index is consulted. Negative indices are folded by adding len(self) once; anything still negative or >= n is rejected.
Source
Thrown at pandas/core/arrays/sparse/array.py:1135
if com.is_bool_indexer(key):
# mypy doesn't know we have an array here
key = cast("np.ndarray", key)
return self.take(np.arange(len(key), dtype=np.int32)[key])
elif hasattr(key, "__len__"):
return self.take(key)
else:
raise ValueError(f"Cannot slice with '{key}'")
return type(self)(data_slice, kind=self.kind)
def _get_val_at(self, loc):
n = len(self)
if loc < 0:
loc += n
if loc >= n or loc < 0:
raise IndexError(
f"index is out of bounds: must be an integer between -{n} and {n - 1}"
)
sp_loc = self.sp_index.lookup(loc)
if sp_loc == -1:
return self.fill_value
else:
val = self.sp_values[sp_loc]
val = maybe_box_datetimelike(val, self.sp_values.dtype)
return val
def take(self, indices, *, allow_fill: bool = False, fill_value=None) -> Self:
if is_scalar(indices):
raise ValueError(f"'indices' must be an array, not a scalar '{indices}'.")
indices = np.asarray(indices, dtype=np.int32)
dtype = None
if indices.size == 0:View on GitHub (pinned to 71959b8cb9)
Solutions
- Clamp/normalize the index before lookup: loc = loc if loc >= 0 else loc + len(arr); assert 0 <= loc < len(arr).
- Use sparse_arr.iloc[loc] semantics via a Series wrapper which standardizes bounds handling.
- Recompute the length at call time instead of reusing a cached n.
Example fix
// before n = len(arr) val = arr._get_val_at(user_pos) # user_pos may exceed n // after loc = user_pos % len(arr) # or an explicit bounds check val = arr._get_val_at(loc)
Defensive patterns
Strategy: validation
Validate before calling
def safe_get_val_at(arr, loc):
n = len(arr)
loc = loc + n if loc < 0 else loc
if not (0 <= loc < n):
raise IndexError(f'loc {loc} out of range for length {n}')
return arr._get_val_at(loc) Type guard
def is_in_bounds(arr, loc) -> bool:
n = len(arr)
return -n <= loc < n Try / catch
try:
val = arr._get_val_at(loc)
except IndexError as e:
if 'out of bounds' in str(e):
# handle missing position
val = arr.fill_value
else:
raise Prevention
- Recompute len(arr) at call time rather than caching
- Normalize negative indices with loc %= len(arr) only when wrapping is intended
- Use Series.iloc for bounds-safe positional access
When it happens
Trigger: Calling _get_val_at(loc) with loc >= len(sparse_arr) or loc < -len(sparse_arr), often indirectly via argmax/argmin internals, repr formatting of a stale cached index, or user code computing positions from a different-length array.
Common situations: Off-by-one loops, using .idxmax() results from one Series to index another of different length, caching a length then appending/trimming the array, or negative indexing math that overshoots (e.g. loc=-n-1).
Related errors
- out of bounds value in 'indices'.
- index {key} is out of bounds for axis 0 with size {n}
- Cannot slice with Ellipsis
- only integers, slices (`:`), ellipsis (`...`), numpy.newaxis
- Cannot slice with '{key}'
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/a163cd25a49a0dfa.
Report an issue: GitHub.