pola-rs/polars · error · NotImplementedError
non-string categories are not supported
Error message
non-string categories are not supported
What it means
For dictionary-encoded categorical columns imported via the interchange protocol, Polars maps categories to an Enum, which requires the categories column itself to be strings (DtypeKind.STRING). If the categories have any other kind (e.g. integer-coded categories), NotImplementedError is raised; only an empty categories column is accepted (mapped to Enum([])).
Solutions
- On the producer, cast the dictionary values to string (pyarrow: pc.cast(col, pa.dictionary(pa.int32(), pa.string()))).
- Import the column as plain integers and re-create the categorical/Enum in Polars yourself via .cast(pl.Enum(...)).
- Convert via pyarrow/pandas first and then pl.from_arrow/pl.from_pandas.
Example fix
# before: pyarrow dictionary with int32 values -> NotImplementedError
tbl = tbl # column 'code' is dictionary<int32, int32>
# after
import pyarrow as pa, pyarrow.compute as pc
i = tbl.schema.get_field_index("code")
tbl = tbl.set_column(i, "code", pc.cast(tbl.column(i), pa.dictionary(pa.int32(), pa.string())))
df = pl.from_dataframe(tbl.__dataframe__()) Defensive patterns
Strategy: validation
Validate before calling
def categories_are_strings(col) -> bool:
if col.dtype[0] != DtypeKind.CATEGORICAL:
return True
cat = col.describe_categorical()
if not cat.get("is_dictionary"):
return False
categories = cat["categories"]
return categories.size() == 0 or categories.dtype[0] == DtypeKind.STRING
ok = all(categories_are_strings(icdf.get_column(i)) for i in range(icdf.num_columns())) Try / catch
try:
df = pl.from_dataframe(obj)
except NotImplementedError as e:
if "non-string categories" not in str(e):
raise
# cast the dictionary values to string on the producer (e.g. pyarrow pc.cast), then retry Prevention
- Dictionary-encode only string values when interoperating with Polars.
- For numeric codes, import as plain integers and rebuild the mapping in Polars.
When it happens
Trigger: pl.from_dataframe(obj) where a dictionary column's categories are integers or other non-strings — e.g. a pyarrow dictionary array whose values type is int32/float, or a producer encoding labels as numeric codes.
Common situations: Storage formats that dictionary-encode numeric values; producers that reuse a generic dictionary encoder regardless of value type; pandas/duckdb pipelines that materialize integer-coded category tables.
Related errors
- non-dictionary categoricals are not yet supported
- data buffer must be cast from
- unsupported data type
- unsupported null type
- unsupported temporal data type
AI-assisted analysis of pola-rs/polars@9b5d73fd00 (2026-08-19).
Data as JSON: /api/errors/e059529f9f26b9fc.
Report an issue: GitHub.
Appendix: source
Thrown at py-polars/src/polars/interchange/from_dataframe.py:157
data = pl.Series._from_buffers(
String, data=data_buffers, validity=validity_buffer
)
return data
def _categorical_column_to_series(column: Column, *, allow_copy: bool) -> Series:
categorical = column.describe_categorical
if not categorical["is_dictionary"]:
msg = "non-dictionary categoricals are not yet supported"
raise NotImplementedError(msg)
categories_col = categorical["categories"]
if categories_col.size() == 0:
dtype = Enum([])
elif categories_col.dtype[0] != DtypeKind.STRING:
msg = "non-string categories are not supported"
raise NotImplementedError(msg)
else:
categories = _string_column_to_series(categories_col, allow_copy=allow_copy)
dtype = Enum(categories)
buffers = column.get_buffers()
offset = column.offset
data_buffer = _construct_data_buffer(
*buffers["data"], column.size(), offset, allow_copy=allow_copy
)
validity_buffer = _construct_validity_buffer(
buffers["validity"], column, dtype, data_buffer, offset, allow_copy=allow_copy
)
# First construct a physical Series without categories
# to allow for sentinel values that do not fit in UInt32
data_dtype = data_buffer.dtype
out = pl.Series._from_buffers(View on GitHub (pinned to 9b5d73fd00)