pandas-dev/pandas · error · TypeError

ExtensionArray.fillna does not support filling with a dict…

Error message

ExtensionArray.fillna does not support filling with a dict. Use Series.fillna instead.

What it means

SparseArray.fillna rejects dict values because dict-based filling is defined only at the Series level (where labels map to fill values), not on the raw ExtensionArray which has no index. The guard explicitly redirects users to Series.fillna.

Solutions

  1. Move the fillna to Series: pd.Series(arr, index=labels).fillna(dict_value).array.
  2. If the dict maps positions to values, convert it to per-position logic and pass a scalar or array to fillna.
  3. Map dict values onto a dense array first, then rebuild the SparseArray.

Example fix

// before
arr.fillna({0: 9.0})  # raises
// after
pd.Series(arr, index=[0, 1, 2]).fillna({0: 9.0}).array
Defensive patterns

Strategy: validation

Validate before calling

def safe_fillna(arr, value=None, **kw):
    if isinstance(value, dict):
        return pd.Series(arr).fillna(value).array
    return arr.fillna(value=value, **kw)

Type guard

def is_dict_fill(value) -> bool:
    return isinstance(value, dict)

Try / catch

try:
    arr.fillna(value)
except TypeError as e:
    if "dict" in str(e):
        arr = pd.Series(arr).fillna(value).array
    else:
        raise

Prevention

When it happens

Trigger: Calling SparseArray.fillna({0: 1.0, 2: 3.0}) or arr.fillna(some_dict); also reached when code forwards a dict to an ExtensionArray.fillna generically.

Common situations: Reusing Series.fillna(value=dict) logic against the underlying .array or .values; refactoring a Series pipeline to operate on the ExtensionArray directly.

Related errors


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

Appendix: source

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

        Returns
        -------
        SparseArray

        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()

View on GitHub (pinned to 3b7651241d)