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
- Call fillna with copy=True (the default) so a writable copy is made before writing.
- If you must mutate in place, first make the buffer writable: arr = arr.copy() or np.asarray(arr).setflags(write=True) before fillna.
- 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
- Default to copy=True for fillna on arrays sourced from buffers/memmaps/frombuffer.
- Copy at the boundary where read-only buffers enter your pipeline (np.asarray(x).copy()).
- Avoid inplace=True fillna on columns from zero-copy slices.
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
- abs(axis) must be less than ndim
- cannot add indices of unequal length
- Cannot modify read-only array
- Accumulation not supported for
- Already tz-aware, use tz_convert to convert.
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_compatView on GitHub (pinned to 3b7651241d)