pandas-dev/pandas · error · AttributeError

Can only use .cat accessor with a 'category' dtype

Error message

Can only use .cat accessor with a 'category' dtype

What it means

Raised by the .cat accessor's _validate when the Series dtype is not CategoricalDtype. The .cat accessor (Series.cat) is registered only for categorical data; accessing it on any other dtype (int, object, datetime, string) raises AttributeError mirroring how pandas accessors gate on dtype. This is a property-accessor guard, not a value check.

Solutions

  1. Convert the Series to categorical first: df['col'] = df['col'].astype('category').
  2. Check dtype before accessing: if isinstance(df['col'].dtype, pd.CategoricalDtype): ...
  3. Verify the column was not silently widened to object by a previous operation (concat, merge, where).
  4. For arrow-backed categoricals, ensure dtype reads as CategoricalDtype, not ArrowDtype.

Example fix

# before
s = pd.Series(['a','b','a'])
s.cat.categories  # AttributeError

# after
s = s.astype('category')
s.cat.categories
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(df['col'].dtype, pd.CategoricalDtype):
    df['col'] = df['col'].astype('category')
df['col'].cat.categories

Type guard

import pandas as pd

def is_categorical(s: pd.Series) -> bool:
    return isinstance(s.dtype, pd.CategoricalDtype)

Prevention

When it happens

Trigger: s.cat.codes where s.dtype != 'category'. df['col'].cat.categories on an object-typed column. Chaining .cat.rename_categories on a column that was never converted. Accessing .cat after an operation that returned object dtype (e.g., .astype(object)).

Common situations: Column was read as object/string instead of category due to mixed types or missing astype. A prior .astype('category') was removed in a refactor. Using pyarrow-backed string dtype ('string[pyarrow]') and expecting .cat to work (it does not — that is a different accessor).

Related errors


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

Appendix: source

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

    2    b
    3    c
    4    c
    5    c
    dtype: category
    Categories (3, str): ['a', 'b', 'c']
    """

    def __init__(self, data) -> None:
        self._validate(data)
        self._parent = data.values
        self._index = data.index
        self._name = data.name
        self._freeze()

    @staticmethod
    def _validate(data) -> None:
        if not isinstance(data.dtype, CategoricalDtype):
            raise AttributeError("Can only use .cat accessor with a 'category' dtype")

    def _delegate_property_get(self, name: str):
        return getattr(self._parent, name)

    def _delegate_property_set(self, name: str, new_values) -> None:
        setattr(self._parent, name, new_values)

    @property
    def codes(self) -> Series:
        """
        Return Series of codes as well as the index.

        The codes are integer indicators for the position of each value in
        the categories. Uncategorized values (i.e., NaN) are assigned a code
        of ``-1``.

        See Also
        --------

View on GitHub (pinned to 3b7651241d)