pandas-dev/pandas · error · ValueError

'values' must be a NumPy array, not {type(values).__name__}

Error message

'values' must be a NumPy array, not {type(values).__name__}

What it means

Raised by NumpyExtensionArray.__init__ when the `values` argument is neither an np.ndarray nor another NumpyExtensionArray. NumpyExtensionArray is the pandas ExtensionArray wrapper around a single NumPy ndarray, so it strictly requires a concrete ndarray backing store. Any other input (list, tuple, scalar, Series) is rejected at construction because the wrapper has no path to coerce it.

Source

Thrown at pandas/core/arrays/numpy_.py:128

    # ExtensionBlock, search for `ABCNumpyExtensionArray`. We check for
    # that _typ to ensure that users don't unnecessarily use EAs inside
    # pandas internals, which turns off things like block consolidation.
    _typ = "npy_extension"
    __array_priority__ = 1000
    _ndarray: np.ndarray
    _dtype: NumpyEADtype
    _internal_fill_value = np.nan

    # ------------------------------------------------------------------------
    # Constructors

    def __init__(
        self, values: np.ndarray | NumpyExtensionArray, copy: bool = False
    ) -> None:
        if isinstance(values, type(self)):
            values = values._ndarray
        if not isinstance(values, np.ndarray):
            raise ValueError(
                f"'values' must be a NumPy array, not {type(values).__name__}"
            )

        if values.ndim == 0:
            # Technically we support 2, but do not advertise that fact.
            raise ValueError("NumpyExtensionArray must be 1-dimensional.")

        if copy:
            values = values.copy()

        dtype = NumpyEADtype(values.dtype)
        super().__init__(values, dtype)

    @classmethod
    def _from_sequence(
        cls, scalars, *, dtype: Dtype | None = None, copy: bool = False
    ) -> NumpyExtensionArray:
        if isinstance(dtype, NumpyEADtype):

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Convert the input to an ndarray first: pd.arrays.NumpyExtensionArray(np.asarray(values)).
  2. Use the public factory pd.array(values) instead of the NumpyExtensionArray constructor directly.
  3. If the input is a list-like, wrap it with np.asarray(values, dtype=...) before passing.

Example fix

# before
pd.arrays.NumpyExtensionArray([1, 2, 3])
# after
pd.arrays.NumpyExtensionArray(np.asarray([1, 2, 3]))
# or simply
pd.array([1, 2, 3])
Defensive patterns

Strategy: type-guard

Validate before calling

import numpy as np

def to_numpy_ea(values):
    if not isinstance(values, (np.ndarray, pd.arrays.NumpyExtensionArray)):
        values = np.asarray(values)
    return pd.arrays.NumpyExtensionArray(values)

Type guard

import numpy as np

def is_ndarray_like(values) -> bool:
    return isinstance(values, (np.ndarray, pd.arrays.NumpyExtensionArray))

Try / catch

try:
    arr = pd.arrays.NumpyExtensionArray(values)
except ValueError:
    arr = pd.arrays.NumpyExtensionArray(np.asarray(values))

Prevention

When it happens

Trigger: Directly constructing pd.arrays.NumpyExtensionArray(<not-an-ndarray>), e.g. passing a Python list, a tuple, a pandas Series, or a scalar value. Also triggered when subclassing NumpyExtensionArray (e.g. StringArray paths) and feeding a non-ndarray result back into type(self)(...).

Common situations: Developers reach for pd.arrays.NumpyExtensionArray by mistake instead of pd.array(...) or pd.Series(...). Passing raw Python lists or a Series into the class constructor. Refactoring code that previously used np.asarray-only paths.

Related errors


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