pandas-dev/pandas · error · ValueError

Cannot modify read-only array

Error message

Cannot modify read-only array

What it means

Raised by `IntervalArray.__setitem__` when the underlying array is marked read-only (`_readonly = True`). The flag is propagated from a parent numpy array that has `writeable=False`, preventing silent data corruption. Fires at pandas/core/arrays/interval.py:696.

Source

Thrown at pandas/core/arrays/interval.py:696

            # scalar
            if is_scalar(left) and isna(left):
                return self._fill_value
            return Interval(left, right, self.closed)
        if np.ndim(left) > 1:
            # GH#30588 multi-dimensional indexer disallowed
            raise ValueError("multi-dimensional indexing not allowed")
        # Argument 2 to "_simple_new" of "IntervalArray" has incompatible type
        # "Union[Period, Timestamp, Timedelta, NaTType, DatetimeArray, TimedeltaArray,
        # ndarray[Any, Any]]"; expected "Union[Union[DatetimeArray, TimedeltaArray],
        # ndarray[Any, Any]]"
        result = self._simple_new(left, right, dtype=self.dtype)  # type: ignore[arg-type]
        if getitem_returns_view(self, key):
            result._readonly = self._readonly
        return result

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

        key = check_array_indexer(self, key)
        value_left, value_right = self._validate_setitem_value(value)

        self._left[key] = value_left
        self._right[key] = value_right

    def _cmp_method(self, other, op):
        # ensure pandas array for list-like and eliminate non-interval scalars
        if is_list_like(other):
            if not isinstance(
                other, (list, np.ndarray, ExtensionArray)
            ) and not ops.has_castable_attr(other):
                warnings.warn(
                    f"Operation with {type(other).__name__} is deprecated. "
                    "In a future version these will be treated as scalar-like. "
                    "To retain the old behavior, explicitly wrap in a Series "
                    "instead.",

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Copy before mutating: `ia = ia.copy()` then assign.
  2. Make the underlying buffer writable: `arr.flags.writeable = True` if you own it.
  3. Build the IntervalArray from a fresh `np.array(source)` instead of the read-only view.

Example fix

// before
ia[0] = pd.Interval(1, 2)  # ia is read-only
// after
ia = ia.copy()
ia[0] = pd.Interval(1, 2)
Defensive patterns

Strategy: validation

Validate before calling

def writable_interval_array(ia):
    if getattr(ia, '_readonly', False):
        ia = ia.copy()
    return ia

Type guard

def is_writable(ia) -> bool:
    return not getattr(ia, '_readonly', False)

Try / catch

try:
    ia[i] = value
except ValueError as e:
    if "Cannot modify read-only" in str(e):
        ia = ia.copy()
        ia[i] = value
    else:
        raise

Prevention

When it happens

Trigger: Calling `ia[i] = value` on an IntervalArray constructed from a read-only numpy buffer (e.g., shared memory, mmap, or `.flags.writeable=False`); or after slicing a parent that shares memory with a read-only source.

Common situations: Loading read-only memory-mapped arrays, parquet/arrow zero-copy buffers, or numpy arrays explicitly frozen for thread-safety.

Related errors


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