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 Categorical.__array__ when called with copy=False (e.g. np.asarray(cat, copy=False)). A Categorical's materialized ndarray is always produced by gathering categories by code (take_nd), which necessarily creates a new array; there is no zero-copy path to the underlying buffer, so pandas cannot honor the no-copy request and raises rather than silently copying.

Source

Thrown at pandas/core/arrays/categorical.py:1786

            if dtype==None (default), the same dtype as
            categorical.categories.dtype.

        See Also
        --------
        numpy.asarray : Convert input to numpy.ndarray.

        Examples
        --------

        >>> cat = pd.Categorical(["a", "b"], ordered=True)

        The following calls ``cat.__array__``

        >>> np.asarray(cat)
        array(['a', 'b'], dtype=object)
        """
        if copy is False:
            raise ValueError(
                "Unable to avoid copy while creating an array as requested."
            )

        ret = take_nd(self.categories._values, self._codes)
        # When we're a Categorical[ExtensionArray], like Interval,
        # we need to ensure __array__ gets all the way to an
        # ndarray.

        # `take_nd` should already make a copy, so don't force again.
        return np.asarray(ret, dtype=dtype)

    def __array_ufunc__(self, ufunc: np.ufunc, method: str, *inputs, **kwargs):
        # for binary ops, use our custom dunder methods
        result = arraylike.maybe_dispatch_ufunc_to_dunder_op(
            self, ufunc, method, *inputs, **kwargs
        )
        if result is not NotImplemented:
            return result

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Allow the copy: `np.asarray(cat)` (default copy=True) or `np.array(cat)`.
  2. If you only need codes, use `cat.codes` (a view of the int buffer, no gather).
  3. Access categories directly via `cat.categories._values` if you want the category buffer rather than materialized values.

Example fix

# before
import numpy as np
cat = pd.Categorical(['a','b','a'])
np.asarray(cat, copy=False)
# after
import numpy as np
cat = pd.Categorical(['a','b','a'])
np.asarray(cat)  # allow the copy
Defensive patterns

Strategy: fallback

Validate before calling

import numpy as np

def to_numpy_cat(cat, copy=True):
    try:
        return np.asarray(cat) if not copy else np.array(cat)
    except ValueError:
        return np.array(cat)

Type guard

def supports_no_copy(x) -> bool:
    import pandas as pd
    return not isinstance(getattr(x, 'dtype', None), pd.CategoricalDtype)

Try / catch

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

Prevention

When it happens

Trigger: `np.asarray(cat, copy=False)` or `np.array(cat, copy=False)` where cat is a Categorical. Also any library that passes copy=False to __array__ expecting a view.

Common situations: Interfacing with libraries that request zero-copy conversion for performance (e.g. some array protocols); explicitly trying to avoid allocations on hot paths.

Related errors


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