pandas-dev/pandas · error · ValueError

Cannot modify read-only array

Error message

Cannot modify read-only array

What it means

`ValueError('Cannot modify read-only array')` raised by the in-place `sort()` method of `NDArrayBackedExtensionArray`. pandas marks arrays that are views onto immutable storage (e.g. blocks shared from another array, or arrays explicitly flagged) with `self._readonly = True`; an in-place reordering would mutate memory the array does not own. The guard fires before `self._ndarray[:] = self._ndarray[sort_indices]`.

Solutions

  1. Sort out-of-place instead: `arr.sort_values()` / `Series.sort_values()` return a new object.
  2. Operate on an explicit copy: `arr = arr.copy(); arr.sort(...)`.
  3. If you built the array yourself, ensure it owns its ndarray (do not set `_readonly=True`) before in-place mutation.

Example fix

// before
arr.sort(...)   # arr._readonly is True -> ValueError

// after
arr = arr.copy()
arr.sort(...)
# or simply
sorted_arr = arr[axt.argsort(...)]
Defensive patterns

Strategy: validation

Validate before calling

if getattr(arr, '_readonly', False):
    arr = arr.copy()
arr.sort(...)

Type guard

def is_mutable(arr) -> bool:
    return not getattr(arr, '_readonly', False)

Try / catch

try:
    arr.sort(...)
except ValueError as e:
    if 'read-only' in str(e):
        arr = arr.copy()
        arr.sort(...)
    else:
        raise

Prevention

When it happens

Trigger: Calling `.sort(...)` (the EA-level in-place sort) — or the public paths that delegate to it — on an array that pandas has flagged read-only. Commonly reached when sorting a Series/Index whose underlying block is a view, or after operations that hand back a read-only backing array.

Common situations: Operating on a Series/Index that shares memory with a DataFrame block pandas froze; chaining `.sort_values(inplace=True)` style operations; receiving an EA from an internal API that sets `_readonly` for copy-on-write safety.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/63f6255712af0015. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/arrays/_mixins.py:243

        # override base class by adding axis keyword
        validate_bool_kwarg(skipna, "skipna")
        if not skipna and self._hasna:
            raise ValueError("Encountered an NA value with skipna=False")
        return nargminmax(self, "argmax", axis=axis)

    def unique(self) -> Self:
        new_data = unique(self._ndarray)
        return self._from_backing_data(new_data)

    def sort(
        self,
        *,
        ascending: bool = True,
        kind: SortKind = "quicksort",
        na_position: str = "last",
    ) -> None:
        if self._readonly:
            raise ValueError("Cannot modify read-only array")
        sort_indices = self.argsort(
            ascending=ascending, kind=kind, na_position=na_position
        )
        self._ndarray[:] = self._ndarray[sort_indices]

    @classmethod
    def _concat_same_type(
        cls,
        to_concat: Sequence[Self],
        axis: AxisInt = 0,
    ) -> Self:
        """
        Concatenate multiple arrays of this dtype.

        Parameters
        ----------
        to_concat : sequence of this type

View on GitHub (pinned to 3b7651241d)