{"record":{"id":"e059529f9f26b9fc","repo":"pola-rs/polars","slug":"non-string-categories-are-not-supported","errorCode":null,"errorMessage":"non-string categories are not supported","messagePattern":"non-string categories are not supported","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/interchange/from_dataframe.py","lineNumber":157,"sourceCode":"        data = pl.Series._from_buffers(\n            String, data=data_buffers, validity=validity_buffer\n        )\n\n    return data\n\n\ndef _categorical_column_to_series(column: Column, *, allow_copy: bool) -> Series:\n    categorical = column.describe_categorical\n    if not categorical[\"is_dictionary\"]:\n        msg = \"non-dictionary categoricals are not yet supported\"\n        raise NotImplementedError(msg)\n\n    categories_col = categorical[\"categories\"]\n    if categories_col.size() == 0:\n        dtype = Enum([])\n    elif categories_col.dtype[0] != DtypeKind.STRING:\n        msg = \"non-string categories are not supported\"\n        raise NotImplementedError(msg)\n    else:\n        categories = _string_column_to_series(categories_col, allow_copy=allow_copy)\n        dtype = Enum(categories)\n\n    buffers = column.get_buffers()\n    offset = column.offset\n\n    data_buffer = _construct_data_buffer(\n        *buffers[\"data\"], column.size(), offset, allow_copy=allow_copy\n    )\n    validity_buffer = _construct_validity_buffer(\n        buffers[\"validity\"], column, dtype, data_buffer, offset, allow_copy=allow_copy\n    )\n\n    # First construct a physical Series without categories\n    # to allow for sentinel values that do not fit in UInt32\n    data_dtype = data_buffer.dtype\n    out = pl.Series._from_buffers(","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/pola-rs/polars/blob/9b5d73fd00236295624374b075d16b1fe6ec6df9/py-polars/src/polars/interchange/from_dataframe.py#L139-L175","documentation":"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([])).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before: pyarrow dictionary with int32 values -> NotImplementedError\ntbl = tbl  # column 'code' is dictionary<int32, int32>\n\n# after\nimport pyarrow as pa, pyarrow.compute as pc\ni = tbl.schema.get_field_index(\"code\")\ntbl = tbl.set_column(i, \"code\", pc.cast(tbl.column(i), pa.dictionary(pa.int32(), pa.string())))\ndf = pl.from_dataframe(tbl.__dataframe__())","handlingStrategy":"validation","validationCode":"def categories_are_strings(col) -> bool:\n    if col.dtype[0] != DtypeKind.CATEGORICAL:\n        return True\n    cat = col.describe_categorical()\n    if not cat.get(\"is_dictionary\"):\n        return False\n    categories = cat[\"categories\"]\n    return categories.size() == 0 or categories.dtype[0] == DtypeKind.STRING\n\nok = all(categories_are_strings(icdf.get_column(i)) for i in range(icdf.num_columns()))","typeGuard":null,"tryCatchPattern":"try:\n    df = pl.from_dataframe(obj)\nexcept NotImplementedError as e:\n    if \"non-string categories\" not in str(e):\n        raise\n    # cast the dictionary values to string on the producer (e.g. pyarrow pc.cast), then retry","preventionTips":["Dictionary-encode only string values when interoperating with Polars.","For numeric codes, import as plain integers and rebuild the mapping in Polars."],"tags":["polars","interchange-protocol","categorical","enum","notimplementederror"],"backgroundTag":"categorical-interchange-unsupported","analyzedSha":"9b5d73fd00236295624374b075d16b1fe6ec6df9","analyzedAt":"2026-08-19T12:15:06.350Z","contentChangedAt":"2026-08-19T12:15:06.350Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}