pola-rs/polars · error · TypeError
`describe_categorical` only works on categorical columns
Error message
`describe_categorical` only works on categorical columns
What it means
Raised by PolarsColumn.describe_categorical in the interchange protocol when the column's dtype is neither Categorical nor Enum. The method exists specifically to expose category metadata, so numeric/String/temporal columns are rejected with a TypeError.
Source
Thrown at py-polars/src/polars/interchange/column.py:78
def describe_categorical(self) -> CategoricalDescription:
"""
Description of the categorical data type of the column.
Raises
------
TypeError
If the data type of the column is not categorical.
"""
dtype = self._col.dtype
if isinstance(dtype, Categorical):
categories = self._col.unique().drop_nulls().cast(String)
is_ordered = False
elif isinstance(dtype, Enum):
categories = dtype.categories
is_ordered = True
else:
msg = "`describe_categorical` only works on categorical columns"
raise TypeError(msg)
return {
"is_ordered": is_ordered,
"is_dictionary": True,
"categories": PolarsColumn(categories, allow_copy=self._allow_copy),
}
@property
def describe_null(self) -> tuple[ColumnNullType, int | None]:
"""Description of the null representation the column uses."""
if self.null_count == 0:
return ColumnNullType.NON_NULLABLE, None
else:
return ColumnNullType.USE_BITMASK, 0
@property
def null_count(self) -> int:
"""The number of null elements."""View on GitHub (pinned to df599052da)
Solutions
- Guard the call: only invoke describe_categorical when the dtype is Categorical or Enum
- Cast beforehand if dictionary semantics are wanted: df.with_columns(pl.col('s').cast(pl.Categorical))
- In consumers, rely on the interchange dtype kind (CATEGORICAL) rather than assuming string columns are categorical
Example fix
// before
info = interchange_col.describe_categorical() # on a String column
// after
from polars.datatypes import Categorical, Enum
if isinstance(interchange_col._col.dtype, (Categorical, Enum)):
info = interchange_col.describe_categorical() Defensive patterns
Strategy: type-guard
Validate before calling
from polars.datatypes import Categorical, Enum
if isinstance(column._col.dtype, (Categorical, Enum)):
info = column.describe_categorical() Type guard
def is_categorical_column(col) -> bool:
from polars.datatypes import Categorical, Enum
return isinstance(col._col.dtype, (Categorical, Enum)) Try / catch
try:
info = col.describe_categorical()
except TypeError:
info = None # not dictionary-encoded; treat as plain values Prevention
- Gate describe_categorical behind a dtype check in consumer code
- Use the interchange dtype kind flags to decide, not column names
When it happens
Trigger: Calling describe_categorical() on an interchange column backed by String, Int64, or any non-categorical dtype; interchange consumers that unconditionally query categorical metadata for dictionary-encoded columns marked via the data kind flags; iterating columns and calling describe_categorical based on is_dictionary heuristics.
Common situations: Writing a generic interchange consumer that assumes any object/string column is dictionary-encoded; converting polars data for libraries expecting dictionary encoding; schema drift where a column that used to be Categorical arrives as String.
Related errors
- `indices` is not a sequence
- `names` is not a sequence
- non-dictionary categoricals are not yet supported
- non-string categories are not supported
- data buffer must be cast from {data_dtype} to UInt32
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/466b9f2a8563e508.
Report an issue: GitHub.