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
- Take a writable copy before mutating: writable = string_array.copy(); writable[i] = value.
- Use Series-level assignment which copies as needed: series.loc[i] = value.
- 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
- Call .copy() before mutating arrays obtained from slices, .values, or astype.
- Prefer Series-level assignment (.loc, .iloc) which handles copy semantics.
- Treat _readonly arrays as immutable views; rebuild rather than mutate.
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
- Cannot modify read-only array
- Cannot modify read-only array
- Cannot modify read-only array
- Invalid value for dtype 'str'. Value should be a string or…
- setting an array element with a sequence.
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_valueView on GitHub (pinned to 3b7651241d)