pola-rs/polars · error · NotImplementedError

non-string categories are not supported

Error message

non-string categories are not supported

What it means

The categories of a dictionary-encoded categorical column must be strings. When the categories column's dtype kind is not DtypeKind.STRING (for example integer category codes), Polars cannot build the Enum type it uses for interchange categoricals and raises NotImplementedError. An empty categories column is accepted and maps to Enum([]).

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 df599052da)

Solutions

  1. Make the producer expose string categories (cast integer codes to their string labels at the source)
  2. Import the column as plain integers and apply the mapping in Polars afterwards with cast to Enum(['a','b',...]) using the known category list

Example fix

// before
# producer exposes integer category codes -> NotImplementedError
pl.from_dataframe(producer_df)

// after
# import codes as integers, map to Enum in polars
df = pl.from_dataframe(producer_df_without_categorical)
df = df.with_columns(pl.col('code').cast(pl.Enum(['foo', 'bar', 'baz'])))
Defensive patterns

Strategy: validation

Validate before calling

def categories_are_strings(df) -> bool:
    from polars.interchange.protocol import DtypeKind
    proto = df.__dataframe__(allow_copy=False)
    for col in proto.get_columns():
        if col.dtype[0] == DtypeKind.CATEGORICAL:
            cats = col.describe_categorical()['categories']
            if cats.size() > 0 and cats.dtype[0] != DtypeKind.STRING:
                return False
    return True

Try / catch

try:
    out = pl.from_dataframe(df)
except NotImplementedError as e:
    if 'non-string categories' in str(e):
        out = pl.from_dataframe(df_without_categorical_col)  # import raw codes
        out = out.with_columns(pl.col('code').cast(known_enum))
    else:
        raise

Prevention

When it happens

Trigger: Dictionary-encoded column whose describe_categorical()['categories'].dtype[0] is not DtypeKind.STRING (e.g. INT category keys from the producer).

Common situations: Producers that store label-encoded vocabularies with integer keys (ML feature stores, database ENUM types with numeric codes); mapping legacy categorical encodings into polars.

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/e059529f9f26b9fc. Report an issue: GitHub.