pandas-dev/pandas · error · IndexError
cannot do a non-empty take
Error message
cannot do a non-empty take
What it means
ExtensionArray.take with allow_fill semantics refuses to produce a non-empty result from an empty source array: if self._pa_array has length 0 but any requested index is >= 0 (a real position, not a fill marker), there is nothing to copy from. This is distinct from out-of-bounds: it specifically catches the empty-input degenerate case before the bounds check.
Solutions
- Guard upstream: check len(arr) > 0 before calling take/reindex, or filter the requested indices to only fill positions.
- Construct the target array so it is non-empty before the operation.
- Use Series.reindex with a fill_value on a non-empty source instead of taking from an empty one.
Example fix
// before
arr = pd.array([], dtype="int64[pyarrow]")
arr.take([0, 1], allow_fill=True)
// after
arr = pd.array([], dtype="int64[pyarrow]")
if len(arr) > 0:
arr.take([0, 1], allow_fill=True) Defensive patterns
Strategy: validation
Validate before calling
def safe_take(arr, indices, allow_fill=False, fill_value=None):
if len(arr) == 0:
if allow_fill and fill_value is not None:
n = len(indices)
return type(arr)([fill_value] * n, dtype=arr.dtype)
return arr.take(indices, allow_fill=False)
return arr.take(indices, allow_fill=allow_fill, fill_value=fill_value) Type guard
def take_is_safe(arr, indices) -> bool:
import numpy as np
if len(arr) == 0:
return not (np.asanyarray(indices) >= 0).any()
return True Try / catch
try:
arr.take(indices, allow_fill=True)
except IndexError as e:
if "non-empty take" in str(e):
# produce a filled result manually
...
raise Prevention
- Check len(arr) > 0 before reindex/take with allow_fill.
- Filter indices to fill-only (-1) when the source is empty.
When it happens
Trigger: Calling .take(indices) or .reindex(...) with allow_fill on a zero-length ArrowExtensionArray where indices contains at least one non-negative entry, e.g. empty_arr.take([0, -1]).
Common situations: Reindexing an empty DataFrame/Series against a non-empty target; take() on dynamically-filtered arrays that ended up empty; fill_value-based reindex on empty frames.
Related errors
- out of bounds value in 'indices'.
- index is out of bounds for axis 0 with size
- ambiguous is not supported.
- is not supported
- ArrowStringArray requires a PyArrow (chunked) array of…
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/4c59940c4ed35bb2.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/arrow/array.py:2091
When `indices` contains negative values other than ``-1``
and `allow_fill` is True.
See Also
--------
numpy.take
api.extensions.take
Notes
-----
ExtensionArray.take is called by ``Series.__getitem__``, ``.loc``,
``iloc``, when `indices` is a sequence of values. Additionally,
it's called by :meth:`Series.reindex`, or any other method
that causes realignment, with a `fill_value`.
"""
indices_array = np.asanyarray(indices)
if len(self._pa_array) == 0 and (indices_array >= 0).any():
raise IndexError("cannot do a non-empty take")
if indices_array.size > 0 and indices_array.max() >= len(self._pa_array):
raise IndexError("out of bounds value in 'indices'.")
if allow_fill:
fill_mask = indices_array < 0
if fill_mask.any():
validate_indices(indices_array, len(self._pa_array))
# TODO(ARROW-9433): Treat negative indices as NULL
indices_array = pa.array(indices_array, mask=fill_mask)
result = self._pa_array.take(indices_array)
if isna(fill_value):
return self._from_pyarrow_array(result)
# TODO: ArrowNotImplementedError: Function fill_null has no
# kernel matching input types (array[string], scalar[string])
result = self._from_pyarrow_array(result)
result[fill_mask] = fill_value
return result
# return type(self)(pc.fill_null(result, pa.scalar(fill_value)))View on GitHub (pinned to 3b7651241d)