pandas-dev/pandas · error · ValueError

Unable to avoid copy while creating an array as requested.

Error message

Unable to avoid copy while creating an array as requested.

What it means

Raised by BaseMaskedArray.__array__ when called with copy=False (numpy's no-copy contract) on an array that contains missing values. A masked array cannot expose a single concrete ndarray without either filling the NAs or copying, so when hasna is True the no-copy request is impossible to honor.

Solutions

  1. Allow a copy: use np.asarray(arr) or arr.to_numpy() with default copy semantics.
  2. Drop or fill NAs before the no-copy conversion: arr.dropna().__array__(copy=False).
  3. Request object dtype explicitly when NAs must be preserved under copy=False on a no-NA subset.

Example fix

// before
np.asarray(arr_with_na, copy=False)   # raises via __array__
// after
np.asarray(arr_with_na)                # copy allowed
Defensive patterns

Strategy: validation

Validate before calling

if arr._hasna:
    out = np.asarray(arr)   # allow copy
else:
    out = arr.__array__(copy=False)

Type guard

def supports_no_copy(arr) -> bool:
    return not arr._hasna

Try / catch

try:
    out = np.asarray(arr, copy=False)
except ValueError as e:
    if 'Unable to avoid copy' in str(e):
        out = np.asarray(arr)
    else:
        raise

Prevention

When it happens

Trigger: Code paths that invoke np.asarray(arr, copy=False) or any ufunc/operation requesting copy=False on a masked ExtensionArray with self._hasna True; explicit arr.__array__(copy=False).

Common situations: NumPy 2.0 copy=False semantics forwarded into pandas masked arrays; libraries calling np.asarray(values, copy=False) to avoid allocation; ufunc dispatch that explicitly forbids copies.

Related errors


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

Appendix: source

Thrown at pandas/core/arrays/masked.py:831

    __array_priority__ = 1000  # higher than ndarray so ops dispatch to us

    def __array__(
        self, dtype: NpDtype | None = None, copy: bool | None = None
    ) -> np.ndarray:
        """
        the array interface, return my values
        We return an object array here to preserve our scalar values
        """
        if copy is False:
            if not self._hasna:
                # special case, here we can simply return the underlying data
                result = np.array(self._data, dtype=dtype, copy=copy)
                # If the ExtensionArray is readonly, make the numpy array readonly too
                if self._readonly:
                    result = result.view()
                    result.flags.writeable = False
                return result
            raise ValueError(
                "Unable to avoid copy while creating an array as requested."
            )

        if copy is None:
            copy = False  # The NumPy copy=False meaning is different here.
        return self.to_numpy(dtype=dtype, copy=copy)

    _HANDLED_TYPES: tuple[type, ...]

    def __array_ufunc__(self, ufunc: np.ufunc, method: str, *inputs, **kwargs):
        # For MaskedArray inputs, we apply the ufunc to ._data
        # and mask the result.

        out = kwargs.get("out", ())

        for x in inputs + out:
            if not isinstance(x, (*self._HANDLED_TYPES, BaseMaskedArray)):
                return NotImplemented

View on GitHub (pinned to 3b7651241d)