pandas-dev/pandas · error · ValueError
new categories need to have the same number of items as the
Error message
new categories need to have the same number of items as the old categories!
What it means
Raised by the internal _set_categories (invoked by the `.categories` property setter) when the new categories list has a different length than the current categories. Renaming via the setter requires a 1:1 replacement; adding/removing categories changes the code mapping and must use the dedicated methods.
Source
Thrown at pandas/core/arrays/categorical.py:987
>>> c
['a', 'b']
Categories (2, str): ['a', 'b']
>>> c._set_categories(pd.Index(["a", "c"]))
>>> c
['a', 'c']
Categories (2, str): ['a', 'c']
"""
if fastpath:
new_dtype = CategoricalDtype._from_fastpath(categories, self.ordered)
else:
new_dtype = CategoricalDtype(categories, ordered=self.ordered)
if (
not fastpath
and self.dtype.categories is not None
and len(new_dtype.categories) != len(self.dtype.categories)
):
raise ValueError(
"new categories need to have the same number of "
"items as the old categories!"
)
super().__init__(self._ndarray, new_dtype)
def _set_dtype(self, dtype: CategoricalDtype, *, copy: bool) -> Self:
"""
Internal method for directly updating the CategoricalDtype
Parameters
----------
dtype : CategoricalDtype
Notes
-----
We don't do any validation here. It's assumed that the dtype is
a (valid) instance of `CategoricalDtype`.View on GitHub (pinned to 71959b8cb9)
Solutions
- To rename in place, supply exactly len(cat.categories) new labels: `cat.categories = ['x','y']` (match count).
- To add categories use `cat = cat.add_categories([...])`.
- To remove use `cat = cat.remove_categories([...])` or `remove_unused_categories()`.
- To fully replace use `cat = cat.set_categories([...])`.
Example fix
# before cat = pd.Categorical(['a','b'], categories=['a','b']) cat.categories = ['x', 'y', 'z'] # after cat = pd.Categorical(['a','b'], categories=['a','b']) cat.categories = ['x', 'y']
Defensive patterns
Strategy: validation
Validate before calling
def safe_set_categories(cat, new_categories):
if len(new_categories) != len(cat.categories):
raise ValueError(f"expected {len(cat.categories)} categories, got {len(new_categories)}")
cat.categories = new_categories
return cat Type guard
def same_category_count(cat, new_categories) -> bool:
return len(new_categories) == len(cat.categories) Try / catch
try:
cat.categories = new_cats
except ValueError as e:
if 'same number of items' in str(e):
cat = cat.set_categories(new_cats)
else:
raise Prevention
- Use the .categories setter only for 1:1 renames.
- Use add_categories/remove_categories/set_categories for membership changes.
- Verify len(new) == len(cat.categories) before assigning.
When it happens
Trigger: `cat.categories = ['x','y','z']` when the current categories have 2 (or 4) entries. The setter delegates to _set_categories which enforces equal length.
Common situations: Renaming categories but accidentally dropping or adding one; chaining operations that change category count then assigning back via `.categories`.
Related errors
- Lengths must match.
- Lengths must match
- Cannot convert float NaN to integer
- Cannot cast {self.categories.dtype} dtype to {dtype}
- The categories must be provided in 'categories' or 'dtype'.
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/c0c43ffd8ef8cb39.
Report an issue: GitHub.