pandas-dev/pandas · error · ValueError
'indices' must be an array, not a scalar '{indices}'.
Error message
'indices' must be an array, not a scalar '{indices}'. What it means
Raised by SparseArray.take when the `indices` argument is a Python/numpy scalar. The take protocol (NEP 29 / ExtensionArray.take) requires a 1-d array of positions because it must build a new SparseArray of the same length as indices; a single scalar has no length to drive that. Pandas raises explicitly rather than letting np.asarray produce a 0-d array that later fails confusingly.
Source
Thrown at pandas/core/arrays/sparse/array.py:1149
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:
result = np.array([], dtype="object")
dtype = self.dtype
elif allow_fill:
result = self._take_with_fill(indices, fill_value=fill_value)
else:
return self._take_without_fill(indices)
return type(self)(
result, fill_value=self.fill_value, kind=self.kind, dtype=dtype
)
def _take_with_fill(self, indices, fill_value=None) -> np.ndarray:
if fill_value is None:
fill_value = self.dtype.na_valueView on GitHub (pinned to 71959b8cb9)
Solutions
- Pass a 1-d array: sparse_arr.take([2]) or sparse_arr.take(np.array([2], dtype=np.int32)).
- For single-position access use sparse_arr._get_val_at(int(idx)) or wrap the array in a Series and use .iloc[int(idx)].
- Normalize at the boundary: idx = np.atleast_1d(np.asarray(idx, dtype=np.int32)) before calling take.
Example fix
// before val = sparse_arr.take(3) # raises 'indices must be an array' // after val = sparse_arr.take([3])
Defensive patterns
Strategy: validation
Validate before calling
import numpy as np
def take_safe(arr, indices):
idx = np.atleast_1d(np.asarray(indices, dtype=np.int32))
return arr.take(idx) Type guard
import numpy as np
def is_array_indices(indices) -> bool:
return hasattr(indices, '__len__') or np.asarray(indices).ndim >= 1 Try / catch
try:
out = arr.take(indices)
except ValueError as e:
if 'must be an array' in str(e):
out = arr.take([int(indices)])
else:
raise Prevention
- Always pass 1-d arrays to SparseArray.take, never bare scalars
- Wrap helper functions that accept 'index or indices' with np.atleast_1d
- Prefer Series.iloc[pos] for single-position reads
When it happens
Trigger: Calling sparse_arr.take(2), pd.api.extensions.take(arr, 5), or sparse_arr[[2]] where the list was collapsed to a scalar by upstream code. Also from .reindex internals that hand a scalar indexer to take.
Common situations: Mixing scalar .iloc[pos] expectations with the .take API, or writing helper functions that accept 'index or indices' and forward the value unchanged to take.
Related errors
- only integers, slices (`:`), ellipsis (`...`), numpy.newaxis
- cannot do a non-empty take
- out of bounds value in 'indices'.
- Cannot construct {type(self).__name__} from scalar data. Pas
- Cannot slice with Ellipsis
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/b12498609cecc8da.
Report an issue: GitHub.