pandas-dev/pandas · error · ValueError
Cannot modify read-only array
Error message
Cannot modify read-only array
What it means
Raised as ValueError by SparseArray.__setitem__ when the instance is marked read-only (self._readonly is True). Even on writable instances the next line raises TypeError ('does not support item assignment via setitem'), so SparseArray item assignment is unsupported in general; the read-only guard fires first for frozen arrays.
Solutions
- Replace, don't mutate: build a new SparseArray with the modified values.
- If you need mutability, materialize via np.asarray(arr) (which is writable) and rebuild a SparseArray after editing.
- Use pandas Series with a sparse dtype and assign via .loc for index-aligned updates.
Example fix
# before arr[i] = new_value # SparseArray, read-only # after vals = np.asarray(arr).copy() vals[i] = new_value new_arr = pd.arrays.SparseArray(vals, fill_value=arr.fill_value)
Defensive patterns
Strategy: fallback
Validate before calling
def sparse_array_is_writable(sparse_arr) -> bool:
return not getattr(sparse_arr, '_readonly', False) Type guard
def writable_sparse(sparse_arr) -> bool:
return not bool(getattr(sparse_arr, '_readonly', False)) Try / catch
try:
sparse_arr[i] = value
except (ValueError, TypeError):
vals = np.asarray(sparse_arr).copy()
vals[i] = value
sparse_arr = pd.arrays.SparseArray(vals, fill_value=sparse_arr.fill_value) Prevention
- Treat SparseArray as immutable; build a new one for changes.
- Mutate a materialized np.ndarray and re-wrap, not the SparseArray itself.
- Use Series(..., dtype='Sparse[...]') with .loc assignment for in-place-like updates.
When it happens
Trigger: Calling arr[i] = value on a SparseArray exposed via .values/.to_numpy() with writeable=False; mutating a SparseArray returned from a zero-copy path that set the read-only flag.
Common situations: Treating SparseArray like a numpy array and trying in-place writes; reading from a memoryview-backed buffer that pandas marks read-only; libraries that freeze arrays for caching.
Related errors
- Can only use the '.sparse' accessor with Sparse data.
- Cannot construct from scalar data. Pass a sequence instead.
- Cannot modify read-only array
- Cannot modify read-only array
- Column length mismatch
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/c31948fc2f491591.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/sparse/array.py:616
if self.sp_values.dtype.kind == "M":
# However, we *do* special-case the common case of
# a datetime64 with pandas NaT.
if fill_value is NaT:
# Can't put pd.NaT in a datetime64[ns]
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 = FalseView on GitHub (pinned to 3b7651241d)