{"record":{"id":"c31948fc2f491591","repo":"pandas-dev/pandas","slug":"cannot-modify-read-only-array-c31948","errorCode":null,"errorMessage":"Cannot modify read-only array","messagePattern":"Cannot modify read-only array","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/sparse/array.py","lineNumber":611,"sourceCode":"            if self.sp_values.dtype.kind == \"M\":\n                # However, we *do* special-case the common case of\n                # a datetime64 with pandas NaT.\n                if fill_value is NaT:\n                    # Can't put pd.NaT in a datetime64[ns]\n                    unit = np.datetime_data(self.sp_values.dtype)[0]\n                    fill_value = np.datetime64(\"NaT\", unit)  # type: ignore[call-overload]\n            try:\n                dtype = np.result_type(self.sp_values.dtype, type(fill_value))\n            except TypeError:\n                dtype = object\n\n        out = np.full(self.shape, fill_value, dtype=dtype)\n        out[self.sp_index.indices] = self.sp_values\n        return out\n\n    def __setitem__(self, key, value) -> None:\n        if self._readonly:\n            raise ValueError(\"Cannot modify read-only array\")\n        # I suppose we could allow setting of non-fill_value elements.\n        # TODO(SparseArray.__setitem__): remove special cases in\n        # ExtensionBlock.where\n        msg = \"SparseArray does not support item assignment via setitem\"\n        raise TypeError(msg)\n\n    def sort(\n        self,\n        *,\n        ascending: bool = True,\n        kind: SortKind = \"quicksort\",\n        na_position: str = \"last\",\n    ) -> None:\n        raise NotImplementedError(\"SparseArray does not support in-place sort\")\n\n    @classmethod\n    def _from_sequence(\n        cls, scalars, *, dtype: Dtype | None = None, copy: bool = False","sourceCodeStart":593,"sourceCodeEnd":629,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/arrays/sparse/array.py#L593-L629","documentation":"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__.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\narr[0] = 5\n// after\ndense = arr.to_dense(); dense[0] = 5; arr = pd.arrays.SparseArray(dense)","handlingStrategy":"try-catch","validationCode":"import pandas as pd\n\ndef setitem_sparse_safe(arr, idx, value):\n    if getattr(arr, '_readonly', False):\n        arr = arr.copy()\n    dense = arr.to_dense()\n    dense[idx] = value\n    return pd.arrays.SparseArray(dense, dtype=arr.dtype)","typeGuard":"def is_writable_sparse(arr) -> bool:\n    return not getattr(arr, '_readonly', False)","tryCatchPattern":"try:\n    arr[0] = value\nexcept (ValueError, TypeError) as e:\n    if 'read-only' in str(e) or 'setitem' in str(e):\n        dense = arr.to_dense(); dense[0] = value\n        arr = pd.arrays.SparseArray(dense, dtype=arr.dtype)\n    else:\n        raise","preventionTips":["Copy SparseArrays received from numpy interop before mutating.","Rebuild from dense instead of using __setitem__.","Avoid positional mutation; use fillna/where/mask."],"tags":["pandas","sparse","sparse-array","read-only","immutability"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}