pandas-dev/pandas · error · TypeError

Categorical input must be list-like

Error message

Categorical input must be list-like

What it means

Raised in the Categorical constructor when `values` is not list-like (is_list_like returns False). Categoricals wrap a finite enumeration of values, so a single scalar like an int or str cannot form one; pandas requires an iterable of values.

Source

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

    def __init__(
        self,
        values,
        categories=None,
        ordered=None,
        dtype: Dtype | None = None,
        copy: bool = True,
    ) -> None:
        dtype = CategoricalDtype._from_values_or_dtype(
            values, categories, ordered, dtype
        )
        # At this point, dtype is always a CategoricalDtype, but
        # we may have dtype.categories be None, and we need to
        # infer categories in a factorization step further below

        if not is_list_like(values):
            # GH#38433
            raise TypeError("Categorical input must be list-like")

        # null_mask indicates missing values we want to exclude from inference.
        # This means: only missing values in list-likes (not arrays/ndframes).
        null_mask = np.array(False)

        # sanitize input
        vdtype = getattr(values, "dtype", None)
        if isinstance(vdtype, CategoricalDtype):
            if dtype.categories is None:
                dtype = CategoricalDtype(values.categories, dtype.ordered)
        elif isinstance(values, range):
            from pandas.core.indexes.range import RangeIndex

            values = RangeIndex(values)
        elif not isinstance(values, (ABCIndex, ABCSeries, ExtensionArray)):
            values = com.convert_to_list_like(values)
            if isinstance(values, list) and len(values) == 0:
                # By convention, empty lists result in object dtype:

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Wrap the scalar in a list: `pd.Categorical([value])`.
  2. Ensure the input is a list/ndarray/Series/Index before passing; guard with `isinstance(values, (list, tuple, np.ndarray, pd.Series))`.
  3. If the value comes from a DataFrame, pass the column (`df['col']`) rather than `df['col'].iloc[0]`.

Example fix

# before
pd.Categorical('a')
# after
pd.Categorical(['a'])
Defensive patterns

Strategy: type-guard

Validate before calling

from pandas.api.types import is_list_like

def to_categorical(values, **kw):
    if not is_list_like(values):
        values = [values]
    import pandas as pd
    return pd.Categorical(values, **kw)

Type guard

def is_list_like_for_categorical(x) -> bool:
    from pandas.api.types import is_list_like
    return is_list_like(x)

Try / catch

try:
    cat = pd.Categorical(value)
except TypeError as e:
    if 'must be list-like' in str(e):
        cat = pd.Categorical([value])
    else:
        raise

Prevention

When it happens

Trigger: `pd.Categorical(5)`, `pd.Categorical('a')`, or passing any non-iterable object as the first argument. Also when a user accidentally passes a single value where a sequence was intended.

Common situations: Programmatically building a Categorical from a variable that is sometimes a scalar; refactoring code that previously received a list down to a single element without wrapping.

Related errors


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