pola-rs/polars · error · NotImplementedError
unsupported data type
Error message
unsupported data type: {dtype!r} What it means
In the import direction, dtype_to_polars_dtype maps an interchange Dtype tuple (kind, bit_width, format_str, endianness) to a Polars dtype via dtype_to_polars_dtype_map[kind][bit_width], after special-casing DATETIME and CATEGORICAL kinds. Unknown kind/bit-width combinations — e.g. FLOAT16, 128-bit integers, or kinds from newer protocol versions — surface as NotImplementedError chained from a KeyError.
Solutions
- Cast unsupported columns on the producer side to a supported width (e.g. float16 -> float32 in pyarrow before export).
- Upgrade Polars — the supported dtype map grows over releases.
- Catch NotImplementedError per column and convert the offending column via another path (e.g. pyarrow -> pl.from_arrow).
Example fix
# before: obj has a float16 column -> NotImplementedError
df = pl.from_dataframe(obj)
# after: widen on the producer side (pyarrow example)
tbl = tbl.cast({"emb": pa.float32()})
df = pl.from_dataframe(tbl.__dataframe__()) Defensive patterns
Strategy: fallback
Validate before calling
# inspect producer dtypes for kinds/widths Polars maps
import polars.interchange.utils as u
unknown = [
(i, col.dtype) for i in range(icdf.num_columns())
if col_dtype_kind_needs_check(icdf.get_column(i)) # kind/bit_width not in u.dtype_to_polars_dtype_map
]
if unknown:
# cast those columns on the producer (e.g. float16 -> float32) before import
... Try / catch
try:
df = pl.from_dataframe(obj)
except NotImplementedError as e:
if "unsupported data type" not in str(e):
raise
# fall back to the Arrow path, which understands more widths
df = pl.from_arrow(obj_to_pyarrow_table(obj)) Prevention
- Widen float16 to float32 on the producer before interchange export.
- Keep Polars current when consuming from producers on newer protocol revisions.
- Prefer pl.from_arrow for exotic physical layouts.
When it happens
Trigger: pl.from_dataframe(obj) where a producer exposes a dtype Polars' map lacks: float16 columns (common in ML pipelines), exotic widths like uint64-on-nonstandard layouts, or custom DtypeKind values from a protocol fork/newer revision.
Common situations: Ingesting half-precision floats from ML feature stores; producers built on newer protocol revisions than the installed Polars; bit widths like 24 or 128 from specialized formats.
Related errors
- data type not supported by the interchange protocol
- non-dictionary categoricals are not yet supported
- non-string categories are not supported
- unsupported null type
- unsupported temporal data type
AI-assisted analysis of pola-rs/polars@9b5d73fd00 (2026-08-19).
Data as JSON: /api/errors/ddefb6bf02e4ab5f.
Report an issue: GitHub.
Appendix: source
Thrown at py-polars/src/polars/interchange/utils.py:128
},
DtypeKind.STRING: {8: String},
}
def dtype_to_polars_dtype(dtype: Dtype) -> PolarsDataType:
"""Convert interchange protocol data type to Polars data type."""
kind, bit_width, format_str, _ = dtype
if kind == DtypeKind.DATETIME:
return _temporal_dtype_to_polars_dtype(format_str, dtype)
elif kind == DtypeKind.CATEGORICAL:
return Enum
try:
return dtype_to_polars_dtype_map[kind][bit_width]
except KeyError as exc:
msg = f"unsupported data type: {dtype!r}"
raise NotImplementedError(msg) from exc
def _temporal_dtype_to_polars_dtype(format_str: str, dtype: Dtype) -> PolarsDataType:
if (match := re.fullmatch(r"ts([mun]):(.*)", format_str)) is not None:
time_unit = match.group(1) + "s"
time_zone = match.group(2) or None
return Datetime(
time_unit=time_unit, # type: ignore[arg-type]
time_zone=time_zone,
)
elif format_str == "tdD":
return Date
elif format_str == "ttu":
return Time
elif (match := re.fullmatch(r"tD([mun])", format_str)) is not None:
time_unit = match.group(1) + "s"
return Duration(time_unit=time_unit) # type: ignore[arg-type]
View on GitHub (pinned to 9b5d73fd00)