pandas-dev/pandas · error · ValueError

Cannot modify read-only array

Error message

Cannot modify read-only array

What it means

Raised in DatetimeLikeArrayMixin.fillna when copy=False and the underlying ndarray is flagged read-only (self._readonly is True). fillna with an in-place scalar fill reuses self._ndarray to avoid a copy, but writing into a read-only buffer is illegal in numpy, so pandas raises ValueError before attempting the write.

Solutions

  1. Call fillna with copy=True (the default) so a writable copy is made before writing.
  2. If you must mutate in place, first make the buffer writable: arr = arr.copy() or np.asarray(arr).setflags(write=True) before fillna.
  3. Locate where the read-only flag was set (often an upstream np.frombuffer/memmap) and copy at that boundary instead.

Example fix

// before
arr.fillna(pd.NaT, copy=False)  # ValueError if arr is read-only

// after
arr = arr.copy()
arr.fillna(pd.NaT, copy=False)
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np

def safe_fillna(arr, value, copy=False):
    if not copy:
        try:
            writable = arr._ndarray.flags.writeable
        except AttributeError:
            writable = True
        if not writable:
            arr = arr.copy()
    return arr.fillna(value, copy=copy)

Type guard

import numpy as np

def is_writable(arr) -> bool:
    nd = getattr(arr, '_ndarray', None)
    return nd is None or nd.flags.writeable

Try / catch

try:
    arr.fillna(value, copy=False)
except ValueError as e:
    if 'read-only' in str(e):
        arr = arr.copy()
        arr.fillna(value, copy=False)
    else:
        raise

Prevention

When it happens

Trigger: Calling arr.fillna(value, copy=False) or df[col].fillna(value, inplace=True) on a column backed by a read-only buffer — typically an array created from a numpy read-only array (e.g. np.frombuffer, a memory-mapped array, or an array slice marked WRITEABLE=False), or a block shared from a frame that was constructed without copying.

Common situations: Memory-mapped datasets (np.memmap), arrays produced by np.asarray(buf) where buf is immutable, zero-copy slicing of a parent frame that was itself marked read-only; calling .fillna(inplace=True) on such a column.

Related errors


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

Appendix: 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 3b7651241d)