pandas-dev/pandas · error · ValueError

Cannot modify read-only array

Error message

Cannot modify read-only array

What it means

Raised by DatetimeLikeArrayMixin.fillna when copy=False is requested but the backing ndarray is marked read-only (self._readonly is True). Pandas cannot fill NaT sentinels in-place into memory it is not permitted to write to, so it refuses rather than silently producing a wrong result. The error is a ValueError, not a TypeError, because the inputs are otherwise valid.

Source

Thrown at pandas/core/arrays/datetimelike.py:738

            self._check_compatible_with(other)
            other = other._ndarray
        return other

    def fillna(self, value, limit: int | None = None, copy: bool = True) -> Self:
        # Fast path: single-pass Cython using iNaT sentinel. GH#42147
        if lib.is_scalar(value):
            if not self._hasna:
                return self.copy() if copy else self[:]
            try:
                validated = self._validate_setitem_value(value)
            except (ValueError, TypeError):
                pass
            else:
                if copy:
                    new_ndarray = self._ndarray.copy()
                else:
                    if self._readonly:
                        raise ValueError("Cannot modify read-only array")
                    new_ndarray = self._ndarray

                arr_i8 = new_ndarray.view("i8")
                fill_i8 = np.array(validated, dtype=new_ndarray.dtype).view("i8")[()]
                algos.scalar_fillna_inplace(
                    arr_i8, fill_i8, is_datetimelike=True, limit=limit
                )

                return type(self)._simple_new(new_ndarray, dtype=self.dtype)

        return super().fillna(value, limit=limit, copy=copy)

    # ------------------------------------------------------------------
    # Additional array methods
    #  These are not part of the EA API, but we implement them because
    #  pandas assumes they're there.

    @ravel_compat

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Drop the copy=False argument so fillna allocates a fresh writable array (default copy=True).
  2. Make the backing buffer writable before the call: arr = s.array._ndarray; arr.flags.writeable = True (or copy it with arr.copy()).
  3. If you must avoid a copy, call the non-inplace path explicitly: s.fillna(value) and reassign, then operate on the result.
  4. Audit upstream code that produced the read-only array (mmap, np.frombuffer, pyarrow) and either copy at ingestion time or set writeable=True there.

Example fix

// before
s.fillna(pd.Timestamp('2020-01-01'), copy=False)  # ValueError on read-only backing array
// after
s = s.fillna(pd.Timestamp('2020-01-01'))  # copy=True is the default
Defensive patterns

Strategy: validation

Validate before calling

arr = s.array._ndarray
if not arr.flags.writeable and s.isna().any():
    # fillna(copy=False) will fail; force a copy
    s = s.fillna(some_value)  # default copy=True

Type guard

def is_writable_datetimelike(s) -> bool:
    from pandas.api.types import is_datetime64_any_dtype, is_timedelta64_dtype
    backing = getattr(s.array, '_ndarray', None)
    return (
        (is_datetime64_any_dtype(s.dtype) or is_timedelta64_dtype(s.dtype))
        and backing is not None
        and bool(backing.flags.writeable)
    )

Try / catch

try:
    s.fillna(value, copy=False)
except ValueError as e:
    if 'read-only array' in str(e):
        s = s.fillna(value)  # fall back to copy=True
    else:
        raise

Prevention

When it happens

Trigger: Calling s.fillna(value, copy=False) or s.interpolate(...) on a DatetimeIndex/TimedeltaIndex/PeriodIndex whose underlying _ndarray was allocated read-only (e.g. produced via np.frombuffer, memoryview, mmap, or a view of another array's const segment). The fast Cython scalar-fillna path at datetimelike.py:734-747 is entered only when value is scalar and self._hasna is True; inside it, the self._readonly guard at line 737 fires.

Common situations: Interoperating with Arrow/Parquet zero-copy buffers, numpy arrays created with writeable=False, shared-memory or mmap-backed Series, and tests that freeze writability. Also seen after operations that return views (e.g. .iloc without copy) combined with the copy=False keyword on older pandas where the readonly flag was not stripped.

Related errors


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