{"record":{"id":"0567ff71ed387b13","repo":"pandas-dev/pandas","slug":"cannot-modify-read-only-array-0567ff","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/arrow/array.py","lineNumber":1565,"sourceCode":"\n        result = pc.array_sort_indices(\n            self._pa_array, order=order, null_placement=null_placement\n        )\n        np_result = result.to_numpy()\n        return np_result.astype(np.intp, copy=False)\n\n    def sort(\n        self,\n        *,\n        ascending: bool = True,\n        kind: SortKind = \"quicksort\",\n        na_position: str = \"last\",\n    ) -> None:\n        # This override replaces self._pa_array directly, bypassing __setitem__,\n        # so enforce the read-only guard here to stay consistent with it and\n        # with the base ExtensionArray.sort.\n        if self._readonly:\n            raise ValueError(\"Cannot modify read-only array\")\n        sort_indices = self.argsort(\n            ascending=ascending, kind=kind, na_position=na_position\n        )\n        sorted_array = self.take(sort_indices)\n        self._pa_array = sorted_array._pa_array\n        # Invalidate any cache_readonly properties that depend on _pa_array\n        self._cache.clear()\n\n    def _argmin_max(self, skipna: bool, method: str) -> int:\n        if self._pa_array.length() in (0, self._pa_array.null_count) or (\n            self._hasna and not skipna\n        ):\n            # For empty or all null, pyarrow returns -1 but pandas expects TypeError\n            # For skipna=False and data w/ null, pandas expects NotImplementedError\n            # let ExtensionArray.arg{max|min} raise\n            return getattr(super(), f\"arg{method}\")(skipna=skipna)\n\n        data = self._pa_array","sourceCodeStart":1547,"sourceCodeEnd":1583,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/arrow/array.py#L1547-L1583","documentation":"Raised by ArrowExtensionArray.sort when self._readonly is True. The override replaces self._pa_array directly (bypassing __setitem__), so it explicitly re-checks the read-only guard to stay consistent with ExtensionArray.__setitem__ and base ExtensionArray.sort. Read-only arrays are produced by views into other arrays and must not be mutated.","triggerScenarios":"arr.sort() on an array flagged _readonly (e.g. a view returned by another operation, or an array explicitly marked read-only via arr.view()._readonly = True); calling sort_values(inplace=True) on a Series backed by a read-only pyarrow view.","commonSituations":"Chained operations that hand back a read-only view; libraries that mark arrays read-only to enforce immutability; debugging sessions where the user tries to sort in place after slicing produced a view.","solutions":["Operate on a copy: arr.copy().sort(...) or use sort_values without inplace.","Detect read-only state before sorting: if getattr(arr, '_readonly', False): arr = arr.copy().","Use argsort + take to get a sorted copy without mutating: sorted_arr = arr.take(arr.argsort()).","Avoid inplace mutations on views; prefer functional style."],"exampleFix":"# before\nview = arr.view()\nview._readonly = True\nview.sort()  # raises ValueError\n\n# after\nsorted_arr = view.copy()\nsorted_arr.sort()  # or: view.take(view.argsort())","handlingStrategy":"validation","validationCode":"def safe_sort(arr, **kw):\n    if getattr(arr, '_readonly', False):\n        arr = arr.copy()\n    arr.sort(**kw)\n    return arr","typeGuard":"def is_readonly(arr) -> bool:\n    return bool(getattr(arr, '_readonly', False))","tryCatchPattern":null,"preventionTips":["Avoid inplace sort on views; operate on a copy.","Use argsort + take for a sorted copy when read-only state is uncertain.","Check arr._readonly before mutating operations."],"tags":["sorting","readonly","mutation","inplace","validation"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}