pandas-dev/pandas · error · TypeError

requires a Series, Index, ExtensionArray, np.ndarray or…

Error message

{func_name} requires a Series, Index, ExtensionArray, np.ndarray or NumpyExtensionArray got {type(values).__name__}.

What it means

The _ensure_arraylike helper validates that inputs to pandas core algorithms (factorize, unique, value_counts, etc.) are one of the recognized array-like types: Series, Index, ExtensionArray, np.ndarray, or NumpyExtensionArray. If the value is none of these and the calling function is not the isin-targets path (which has its own coercion logic), a TypeError is raised naming the offending type. This guard (GH#52986) prevents opaque downstream failures by failing fast with a descriptive message.

Solutions

  1. Wrap the value in np.asarray() or pd.Series() before passing it to the algorithm function.
  2. If the value is a list, ensure it is actually a list and not a scalar — check type(value) and len(value).
  3. If using a custom container, subclass ExtensionArray or convert to np.ndarray via np.asarray(container).
  4. For generators/iterators, materialize them first: list(gen) or np.fromiter(gen).

Example fix

# before
pd.factorize(my_dict)

# after
pd.factorize(np.asarray(my_values))
Defensive patterns

Strategy: validation

Validate before calling

from pandas.api.types import is_list_like

def ensure_arraylike_for_algo(values):
    if not isinstance(values, (pd.Series, pd.Index, np.ndarray)):
        if is_list_like(values):
            values = np.asarray(values)
        else:
            raise TypeError(f"Expected array-like, got {type(values).__name__}")
    return values

Type guard

def is_pandas_arraylike(values) -> bool:
    return isinstance(
        values,
        (pd.Series, pd.Index, pd.api.extensions.ExtensionArray, np.ndarray)
    )

Try / catch

try:
    result = pd.factorize(values)
except TypeError as e:
    if "requires a Series" in str(e):
        values = np.asarray(values)
        result = pd.factorize(values)
    else:
        raise

Prevention

When it happens

Trigger: Passing a Python scalar, a plain dict, a set, a string, or a custom non-array-like object to a public or internal function that delegates to _ensure_arraylike — e.g., pd.factorize(42), pd.unique("hello"), or pd.Series.tolist()-style calls that inadvertently route a scalar into an algorithm path. Also triggered by passing a generator or iterator where an indexable array-like is required.

Common situations: Refactoring code that previously passed lists (which get coerced) to pass a different non-array-like type. Using a custom container class that does not subclass any recognized pandas/numpy type. Passing a single scalar where a 1-D sequence was intended (e.g., extracting one element instead of a column). Version upgrades where coercion was previously implicit but is now strict (GH#52986 tightened this).

Related errors


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

Appendix: source

Thrown at pandas/core/algorithms.py:239

    # error: Incompatible return value type
    # (got "ndarray[tuple[Any, ...], dtype[Any]]",
    # expected "ExtensionArray")
    return values.astype(dtype, copy=False)  # type: ignore[return-value]


def _ensure_arraylike(values, func_name: str) -> ArrayLike:
    """
    ensure that we are arraylike if not already
    """
    if not isinstance(
        values,
        (ABCIndex, ABCSeries, ABCExtensionArray, np.ndarray, ABCNumpyExtensionArray),
    ):
        # GH#52986
        if func_name != "isin-targets":
            # Make an exception for the comps argument in isin.
            raise TypeError(
                f"{func_name} requires a Series, Index, "
                f"ExtensionArray, np.ndarray or NumpyExtensionArray "
                f"got {type(values).__name__}."
            )

        inferred = lib.infer_dtype(values, skipna=False)
        if inferred in ["mixed", "string", "mixed-integer"]:
            # "mixed-integer" to ensure we do not cast ["ss", 42] to str GH#22160
            if isinstance(values, tuple):
                values = list(values)
            values = construct_1d_object_array_from_listlike(values)
        else:
            values = np.asarray(values)
    return values


_hashtables = {
    "complex128": htable.Complex128HashTable,

View on GitHub (pinned to 3b7651241d)