pola-rs/polars · error · ValueError

data type {dtype!r} not supported by the interchange protoco

Error message

data type {dtype!r} not supported by the interchange protocol

What it means

On the export side (Polars DataFrame exposed through the interchange protocol), polars_dtype_to_dtype maps Polars dtypes to protocol dtype tuples via a lookup map. Types with no protocol representation - nested types (List, Struct, Array), Binary, Time, Null, Object - hit a KeyError that is re-raised as ValueError. Only primitive numeric, boolean, string, datetime, date, duration, categorical and enum types can be exported.

Source

Thrown at py-polars/src/polars/interchange/utils.py:65

    Float64: (DtypeKind.FLOAT, 64, "g", NE),
    Boolean: (DtypeKind.BOOL, 1, "b", NE),
    String: (DtypeKind.STRING, 8, "U", NE),
    Date: (DtypeKind.DATETIME, 32, "tdD", NE),
    Time: (DtypeKind.DATETIME, 64, "ttu", NE),
    Datetime: (DtypeKind.DATETIME, 64, "tsu:", NE),
    Duration: (DtypeKind.DATETIME, 64, "tDu", NE),
    Categorical: (DtypeKind.CATEGORICAL, 32, "I", NE),
    Enum: (DtypeKind.CATEGORICAL, 32, "I", NE),
}


def polars_dtype_to_dtype(dtype: PolarsDataType) -> Dtype:
    """Convert Polars data type to interchange protocol data type."""
    try:
        result = polars_dtype_to_dtype_map[dtype.base_type()]
    except KeyError as exc:
        msg = f"data type {dtype!r} not supported by the interchange protocol"
        raise ValueError(msg) from exc

    # Handle instantiated data types
    if isinstance(dtype, Datetime):
        return _datetime_to_dtype(dtype)
    elif isinstance(dtype, Duration):
        return _duration_to_dtype(dtype)

    return result


def _datetime_to_dtype(dtype: Datetime) -> Dtype:
    tu = dtype.time_unit[0]
    tz = dtype.time_zone if dtype.time_zone is not None else ""
    arrow_c_type = f"ts{tu}:{tz}"
    return DtypeKind.DATETIME, 64, arrow_c_type, NE


def _duration_to_dtype(dtype: Duration) -> Dtype:

View on GitHub (pinned to df599052da)

Solutions

  1. Select or drop unsupported columns before conversion: df.select([c for c, d in zip(df.columns, df.dtypes) if is_exportable(d)])
  2. Cast nested columns to a representable form first (e.g. List -> String via str serialization, or explode them)
  3. Transfer the data with Arrow instead (df.to_arrow()), which supports nested types, instead of the deprecated interchange path

Example fix

// before
df.__dataframe__()  # contains List column -> ValueError

// after
exportable = [name for name, dtype in zip(df.columns, df.dtypes) if dtype.is_integer() or dtype.is_float() or dtype == pl.String or dtype.is_temporal() or dtype == pl.Boolean or dtype in (pl.Categorical, pl.Enum)]
df.select(exportable).__dataframe__()
Defensive patterns

Strategy: validation

Validate before calling

import polars as pl
from polars.interchange.utils import polars_dtype_to_dtype

def exportable_columns(df: pl.DataFrame) -> list[str]:
    names = []
    for name, dtype in zip(df.columns, df.dtypes):
        try:
            polars_dtype_to_dtype(dtype)
        except ValueError:
            continue
        names.append(name)
    return names

# usage: df.select(exportable_columns(df)).__dataframe__()

Type guard

import polars as pl
from polars.interchange.utils import polars_dtype_to_dtype

def dtype_is_interchange_exportable(dtype: pl.DataType) -> bool:
    """True if polars_dtype_to_dtype(dtype) succeeds."""
    try:
        polars_dtype_to_dtype(dtype)
    except ValueError:
        return False
    return True

Try / catch

try:
    proto = df.__dataframe__()
except ValueError as e:
    if 'not supported by the interchange protocol' in str(e):
        raise ValueError(
            f'frame has non-exportable dtypes: {df.schema}'
        ) from e
    raise

Prevention

When it happens

Trigger: Calling df.__dataframe__() on a Polars DataFrame, or passing one to another library's interchange consumer, when the frame contains List/Struct/Array/Binary/Null/Object/Time columns.

Common situations: Feeding polars output into interchange-based consumers (older ibis, vaex, plotting tools); schema drift after group_by/agg/window operations that silently produce List columns; concat growing Null-typed columns.

Related errors


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