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
- Convert the Series to categorical first: df['col'] = df['col'].astype('category').
- Check dtype before accessing: if isinstance(df['col'].dtype, pd.CategoricalDtype): ...
- Verify the column was not silently widened to object by a previous operation (concat, merge, where).
- 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
- Convert columns to 'category' right after loading: df['col'] = df['col'].astype('category').
- After merge/concat, re-check dtypes; categoricals may widen to object.
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
- Can only use the '.sparse' accessor with Sparse data.
- codes need to be array-like integers
- has no 'diff' method. Convert to a suitable dtype prior to…
- > 1 ndim Categorical are not supported at this time
- Accumulation not supported for
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)