pandas-dev/pandas · error · ValueError

Cannot modify read-only array

Error message

Cannot modify read-only array

What it means

Raised by ExtensionArray.__setitem__ when `self._readonly` is True. Several immutable extension arrays (and views flagged readonly after slicing/astype-is-view operations) set _readonly to prevent in-place mutation; any assignment via `arr[i] = value` (including internal use by Series.where on a copy) then raises ValueError. The check runs before any subclass-specific __setitem__ logic.

Source

Thrown at pandas/core/arrays/base.py:569

        # *do* choose to implement __setitem__, then some semantics should be
        # observed:
        #
        # * Setting multiple values : ExtensionArrays should support setting
        #   multiple values at once, 'key' will be a sequence of integers and
        #  'value' will be a same-length sequence.
        #
        # * Broadcasting : For a sequence 'key' and a scalar 'value',
        #   each position in 'key' should be set to 'value'.
        #
        # * Coercion : Most users will expect basic coercion to work. For
        #   example, a string like '2018-01-01' is coerced to a datetime
        #   when setting on a datetime64ns array. In general, if the
        #   __init__ method coerces that value, then so should __setitem__
        # Note, also, that Series/DataFrame.where internally use __setitem__
        # on a copy of the data.
        # Check if the array is readonly
        if self._readonly:
            raise ValueError("Cannot modify read-only array")

        raise NotImplementedError(f"{type(self)} does not implement __setitem__.")

    def __len__(self) -> int:
        """
        Length of this array

        Returns
        -------
        length : int
        """
        raise AbstractMethodError(self)

    def __iter__(self) -> Iterator[Any]:
        """
        Iterate over elements of the array.
        """
        # This needs to be implemented so that pandas recognizes extension

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Force a writable copy before assigning: `s = s.copy(); s.iloc[i] = v`.
  2. Avoid in-place mutation of slices/views; rebuild with pd.concat/where instead.
  3. Check `s.array._readonly` (or equivalent) before attempting mutation.
  4. Use functional updates: `s = s.mask(cond, new_value)` rather than item assignment.

Example fix

# before
s = pd.Series([1,2,3], dtype="Int64")
view = s.astype("Int64")  # may be readonly view
view.iloc[0] = 99  # ValueError: Cannot modify read-only array

# after
view = s.astype("Int64").copy()
view.iloc[0] = 99
Defensive patterns

Strategy: validation

Validate before calling

def safe_setitem(arr, key, value):
    if getattr(arr, "_readonly", False):
        arr = arr.copy()
    arr[key] = value
    return arr

Type guard

def is_readonly(arr) -> bool:
    return bool(getattr(arr, "_readonly", False))

Try / catch

try:
    arr[key] = value
except ValueError as e:
    if "read-only" in str(e):
        arr = arr.copy()
        arr[key] = value
    else:
        raise

Prevention

When it happens

Trigger: Calling `arr[i] = v` or `s.iloc[i] = v` on an immutable extension array (e.g. some ArrowExtensionArray views, categorical copies marked readonly, or arrays explicitly flagged readonly). Triggered internally when pandas tries to use __setitem__ on a readonly view produced by astype/slicing.

Common situations: Mutating a Series that was created from a readonly view; chaining astype followed by in-place assignment; libraries handing pandas readonly buffers; categorical/date arrays marked immutable.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/82ff92e4acd21bb8. Report an issue: GitHub.