pandas-dev/pandas · error · ValueError
Cannot modify read-only array
Error message
Cannot modify read-only array
What it means
Raised in SparseArray.__setitem__ when the instance's _readonly flag is set. pandas marks a SparseArray read-only when it was built from a view of an immutable/read-only buffer (e.g. the no-gap fast path in __array__ propagates the flag), so mutation would corrupt shared memory. It is the first guard in __setitem__.
Source
Thrown at pandas/core/arrays/sparse/array.py:611
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 71959b8cb9)
Solutions
- Copy before mutating: arr = arr.copy(); arr[0] = 5 (note: SparseArray forbids setitem entirely, so prefer rebuilding).
- Rebuild via _from_sequence with modified data instead of setitem.
- Avoid __setitem__ on SparseArray altogether; construct a new SparseArray from the modified dense values.
Example fix
// before arr[0] = 5 // after dense = arr.to_dense(); dense[0] = 5; arr = pd.arrays.SparseArray(dense)
Defensive patterns
Strategy: try-catch
Validate before calling
import pandas as pd
def setitem_sparse_safe(arr, idx, value):
if getattr(arr, '_readonly', False):
arr = arr.copy()
dense = arr.to_dense()
dense[idx] = value
return pd.arrays.SparseArray(dense, dtype=arr.dtype) Type guard
def is_writable_sparse(arr) -> bool:
return not getattr(arr, '_readonly', False) Try / catch
try:
arr[0] = value
except (ValueError, TypeError) as e:
if 'read-only' in str(e) or 'setitem' in str(e):
dense = arr.to_dense(); dense[0] = value
arr = pd.arrays.SparseArray(dense, dtype=arr.dtype)
else:
raise Prevention
- Copy SparseArrays received from numpy interop before mutating.
- Rebuild from dense instead of using __setitem__.
- Avoid positional mutation; use fillna/where/mask.
When it happens
Trigger: arr[0] = 5 on a SparseArray produced by slicing/viewing a read-only source; setting items on an array exposed via .values from a read-only-backed Series; in-place writes after np.asarray(arr) where numpy returned a read-only view.
Common situations: Operating on arrays handed back from numpy interop that mark them non-writeable; multiprocessing/ shared-memory pipelines; defensive read-only flags set by upstream code.
Related errors
- Cannot construct {type(self).__name__} from scalar data. Pas
- 'data' must have a single column, not '{ncol}'
- Unable to avoid copy while creating an array as requested.
- SparseArray does not support item assignment via setitem
- SparseArray does not support in-place sort
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/c31948fc2f491591.
Report an issue: GitHub.