pandas-dev/pandas · error · TypeError

SparseArray does not support item assignment via setitem

Error message

SparseArray does not support item assignment via setitem

What it means

Raised unconditionally in SparseArray.__setitem__ (after the read-only check). SparseArray does not support in-place item assignment at all because updating a single value would require re-deriving the sparse index (sp_values + sp_index), so every setitem is rejected with TypeError. The supported path is to build a new array.

Source

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

                    unit = np.datetime_data(self.sp_values.dtype)[0]
                    fill_value = np.datetime64("NaT", unit)  # type: ignore[call-overload]
            try:
                dtype = np.result_type(self.sp_values.dtype, type(fill_value))
            except TypeError:
                dtype = object

        out = np.full(self.shape, fill_value, dtype=dtype)
        out[self.sp_index.indices] = self.sp_values
        return out

    def __setitem__(self, key, value) -> None:
        if self._readonly:
            raise ValueError("Cannot modify read-only array")
        # I suppose we could allow setting of non-fill_value elements.
        # TODO(SparseArray.__setitem__): remove special cases in
        # ExtensionBlock.where
        msg = "SparseArray does not support item assignment via setitem"
        raise TypeError(msg)

    def sort(
        self,
        *,
        ascending: bool = True,
        kind: SortKind = "quicksort",
        na_position: str = "last",
    ) -> None:
        raise NotImplementedError("SparseArray does not support in-place sort")

    @classmethod
    def _from_sequence(
        cls, scalars, *, dtype: Dtype | None = None, copy: bool = False
    ) -> Self:
        return cls(scalars, dtype=dtype)

    @classmethod
    def _from_factorized(cls, values, original) -> Self:

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Rebuild the SparseArray from modified dense data: new = pd.arrays.SparseArray(np.where(mask, value, arr.to_dense())).
  2. Operate at the Series level with .fillna/.where/.mask which return new objects.
  3. If you only need to fill NAs, use arr.fillna(value) instead of setitem.

Example fix

// before
arr[2] = 99
// after
dense = arr.to_dense(); dense[2] = 99; arr = pd.arrays.SparseArray(dense, dtype=arr.dtype)
Defensive patterns

Strategy: fallback

Validate before calling

import pandas as pd
import numpy as np

def assign_sparse(arr, mask, value):
    dense = arr.to_dense()
    dense = np.where(mask, value, dense)
    return pd.arrays.SparseArray(dense, dtype=arr.dtype)

Type guard

def supports_setitem(arr) -> bool:
    return type(arr).__name__ != 'SparseArray'

Try / catch

try:
    arr[0] = value
except TypeError as e:
    if 'setitem' in str(e):
        dense = arr.to_dense(); dense[0] = value
        arr = pd.arrays.SparseArray(dense, dtype=arr.dtype)
    else:
        raise

Prevention

When it happens

Trigger: sparse_arr[0] = 5; sparse_arr[i] = value in a loop; df['col'] = ... where df['col'].array is a SparseArray and code tries positional writes through .array.

Common situations: Porting dense ndarray/Series code that mutates positions; vectorized fills written as loops; trying to patch a few entries in a sparse column.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/4aacd4bccce657dc. Report an issue: GitHub.