pandas-dev/pandas · error · IndexError

cannot do a non-empty take from an empty axes.

Error message

cannot do a non-empty take from an empty axes.

What it means

IndexError from SparseArray._take_with_fill when the array is empty (len==0) but the caller requested a non-empty take that is not entirely the -1 fill sentinel. Empty source arrays can only honor an all-fill take.

Source

Thrown at pandas/core/arrays/sparse/array.py:1191

        if indices.min() < -1:
            raise ValueError(
                "Invalid value in 'indices'. Must be between -1 "
                "and the length of the array."
            )

        if indices.max() >= len(self):
            raise IndexError("out of bounds value in 'indices'.")

        if len(self) == 0:
            # Empty... Allow taking only if all empty
            if (indices == -1).all():
                dtype = np.result_type(self.sp_values, type(fill_value))
                taken = np.empty_like(indices, dtype=dtype)
                taken.fill(fill_value)
                return taken
            else:
                raise IndexError("cannot do a non-empty take from an empty axes.")

        # sp_indexer may be -1 for two reasons
        # 1.) we took for an index of -1 (new)
        # 2.) we took a value that was self.fill_value (old)
        sp_indexer = self.sp_index.lookup_array(indices)
        new_fill_indices = indices == -1
        old_fill_indices = (sp_indexer == -1) & ~new_fill_indices

        if self.sp_index.npoints == 0 and old_fill_indices.all():
            # We've looked up all valid points on an all-sparse array.
            taken = np.full(
                sp_indexer.shape, fill_value=self.fill_value, dtype=self.dtype.subtype
            )

        elif self.sp_index.npoints == 0:
            # Use the old fill_value unless we took for an index of -1
            _dtype = np.result_type(self.dtype.subtype, type(fill_value))
            if self.dtype.subtype.kind == "b" and _dtype.kind != "b":

View on GitHub (pinned to 3b7651241d)

Solutions

  1. Guard the empty case: if len(arr) == 0: return empty result.
  2. Only take with all -1 sentinels when allow_fill=True on an empty array.
  3. Use pd.Series(arr).reindex(...).fillna(...) which handles empties.

Example fix

// before
pd.arrays.SparseArray([]).take([0], allow_fill=True)  # raises
// after
empty = pd.arrays.SparseArray([])
out = empty.take([-1, -1], allow_fill=True)  # all-fill is allowed
Defensive patterns

Strategy: validation

Validate before calling

def safe_take_empty(arr, indices, fill_value=None):
    if len(arr) == 0:
        import numpy as np
        if np.all(np.asarray(indices) == -1):
            return arr.take(indices, allow_fill=True, fill_value=fill_value)
        return arr  # empty result
    return arr.take(indices, allow_fill=True, fill_value=fill_value)

Type guard

def empty_source(arr) -> bool:
    return len(arr) == 0

Try / catch

try:
    arr.take(indices, allow_fill=True)
except IndexError as e:
    if 'empty axes' in str(e):
        out = arr  # nothing to take
    else:
        raise

Prevention

When it happens

Trigger: pd.arrays.SparseArray([]).take([0], allow_fill=True); any take on an empty sparse Series where indices contains a real position.

Common situations: Branches that forgot to short-circuit on empty input; groupby/reindex paths that produce empty groups but still call take.

Related errors


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