pandas-dev/pandas · error · TypeError

Categorical input must be list-like

Error message

Categorical input must be list-like

What it means

Raised in `Categorical.__init__` when the `values` argument is not list-like (GH#38433). Categoricals represent a 1-D sequence of codes; a scalar or other non-iterable cannot back one, so the constructor refuses early before any dtype inference.

Solutions

  1. Wrap the scalar in a list: `pd.Categorical([value])`.
  2. Validate upstream: ensure the source produces a sequence before passing it in.
  3. Use `pd.Series(value, dtype='category')` if you want a single-element categorical Series.
  4. If the value can legitimately be scalar or list, normalize: `values = [values] if not is_list_like(values) else values`.

Example fix

# before
import pandas as pd
cat = pd.Categorical('a')  # TypeError: Categorical input must be list-like

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

Strategy: validation

Validate before calling

from pandas.api.types import is_list_like

def to_categorical(values, **kwargs):
    if not is_list_like(values):
        values = [values]
    return pd.Categorical(values, **kwargs)

Type guard

from pandas.api.types import is_list_like

def is_categorical_input(values) -> bool:
    return is_list_like(values)

Prevention

When it happens

Trigger: Calling `pd.Categorical(5)`, `pd.Categorical('a')` (single string is technically scalar in this check context), or passing a single datetime/None.

Common situations: Programmatically constructing a Categorical from a function that unexpectedly returned a scalar instead of a sequence; off-by-one indexing that yielded a single cell; refactoring list-building code that sometimes yields a non-iterable.

Related errors


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

Appendix: 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 3b7651241d)