pandas-dev/pandas · error · ValueError

limit must be None

Error message

limit must be None

What it means

SparseArray.fillna raises ValueError when limit is not None. Sparse filling operates on sp_values via np.where, which cannot respect a forward fill limit, so limit is structurally unsupported.

Solutions

  1. Drop the limit argument when calling fillna on a SparseArray.
  2. If limit semantics are required, operate on a dense Series: pd.Series(arr).fillna(value, limit=N), then re-sparse.
  3. Implement limit-aware filling on the dense materialization and rebuild the SparseArray.

Example fix

// before
arr.fillna(0.0, limit=2)  # raises
// after
pd.Series(arr).fillna(0.0, limit=2).astype(pd.SparseDtype()).array
Defensive patterns

Strategy: validation

Validate before calling

def safe_fillna(arr, value=None, limit=None):
    if limit is not None and hasattr(arr, 'sp_index'):  # SparseArray
        return pd.Series(arr).fillna(value, limit=limit).array
    return arr.fillna(value=value, limit=limit)

Type guard

def sparse_rejects_limit(arr, limit) -> bool:
    from pandas.core.arrays.sparse import SparseArray
    return isinstance(arr, SparseArray) and limit is not None

Try / catch

try:
    arr.fillna(value, limit=limit)
except ValueError as e:
    if "limit must be None" in str(e):
        arr = pd.Series(arr).fillna(value, limit=limit).array
    else:
        raise

Prevention

When it happens

Trigger: Calling arr.fillna(value, limit=1) or any fillna with a non-None limit on a SparseArray.

Common situations: Porting dense Series.fillna(value, limit=N) code to a sparse-backed Series; generic fillna wrappers that always forward limit.

Related errors


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

Appendix: source

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

        Notes
        -----
        When `value` is specified, the result's ``fill_value`` depends on
        ``self.fill_value``. The goal is to maintain low-memory use.

        If ``self.fill_value`` is NA, the result dtype will be
        ``SparseDtype(self.dtype, fill_value=value)``. This will preserve
        amount of memory used before and after filling.

        When ``self.fill_value`` is not NA, the result dtype will be
        ``self.dtype``. Again, this preserves the amount of memory used.
        """
        if isinstance(value, dict):
            raise TypeError(
                "ExtensionArray.fillna does not support filling with a dict. "
                "Use Series.fillna instead."
            )
        if limit is not None:
            raise ValueError("limit must be None")
        new_values = np.where(isna(self.sp_values), value, self.sp_values)

        if self._null_fill_value:
            # This is essentially just updating the dtype.
            new_dtype = SparseDtype(self.dtype.subtype, fill_value=value)
        else:
            new_dtype = self.dtype

        return self._simple_new(new_values, self._sparse_index, new_dtype)

    def shift(self, periods: int = 1, fill_value=None) -> Self:
        if not len(self) or periods == 0:
            return self.copy()

        if isna(fill_value):
            fill_value = self.dtype.na_value

        subtype = np.result_type(fill_value, self.dtype.subtype)

View on GitHub (pinned to 3b7651241d)