pandas-dev/pandas · error · ValueError

Cannot modify read-only array

Error message

Cannot modify read-only array

What it means

Thrown by StringArray.__setitem__ in pandas/core/arrays/string_.py:871 when the array's _readonly flag is True. The flag (defined as a class attribute on ExtensionArray, default False) is set to True on arrays produced by view-preserving operations (certain slices, astype-is-view results) to prevent mutating shared backing memory. Any attempted mutation raises ValueError before the value is even validated.

Solutions

  1. Take a writable copy before mutating: writable = string_array.copy(); writable[i] = value.
  2. Use Series-level assignment which copies as needed: series.loc[i] = value.
  3. Avoid mutating arrays obtained from .values / .array directly; rebuild via pd.array(...).

Example fix

// before
s = pd.Series(['a','b'], dtype='string')
v = s.values[:]
v[0] = 'z'  # may raise ValueError if _readonly

// after
writable = s.values.copy()
writable[0] = 'z'
Defensive patterns

Strategy: validation

Validate before calling

import pandas as pd
def writable_string_array(arr):
    if getattr(arr, '_readonly', False):
        arr = arr.copy()
    return arr

Type guard

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

Try / catch

null

Prevention

When it happens

Trigger: Calling .iloc[i] = ... on a StringArray obtained from a no-copy slice (e.g., head(), a boolean mask that returned a view, or astype between compatible dtypes). Mutating an array surfaced by .values or .array on a Series that shares memory with another object. Writing to an array after .astype('string') on a parent that flagged the result read-only.

Common situations: Chained indexing patterns that return views. Arrow-backed or masked arrays propagated _readonly through copy=False paths. Code that previously mutated object-dtype slices freely now failing after migrating to 'string' dtype.

Related errors


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

Appendix: source

Thrown at pandas/core/arrays/string_.py:871

            value = extract_array(value, extract_numpy=True)
            if not is_array_like_deprecate_non_pandas(value):
                value = np.asarray(value, dtype=object)
            elif isinstance(value.dtype, type(self.dtype)):
                return value
            else:
                # cast categories and friends to arrays to see if values are
                # compatible, compatibility with arrow backed strings
                value = np.asarray(value)
            if len(value) and not lib.is_string_array(value, skipna=True):
                raise TypeError(
                    "Invalid value for dtype 'str'. Value should be a "
                    "string or missing value (or array of those)."
                )
        return value

    def __setitem__(self, key, value) -> None:
        if self._readonly:
            raise ValueError("Cannot modify read-only array")

        value = self._validate_setitem_value(value)

        key = check_array_indexer(self, key)
        scalar_key = lib.is_scalar(key)
        scalar_value = lib.is_scalar(value)
        if scalar_key and not scalar_value:
            raise ValueError("setting an array element with a sequence.")

        if not scalar_value:
            if value.dtype == self.dtype:
                value = value._ndarray
            else:
                value = np.asarray(value)
                mask = isna(value)
                if mask.any():
                    value = value.copy()
                    value[isna(value)] = self.dtype.na_value

View on GitHub (pinned to 3b7651241d)