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

  1. Cast unsupported columns on the producer side to a supported width (e.g. float16 -> float32 in pyarrow before export).
  2. Upgrade Polars — the supported dtype map grows over releases.
  3. 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

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


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)