pola-rs/polars · error · TypeError

`df` of type does not support the dataframe interchange…

Error message

`df` of type {qualified_type_name(df)!r} does not support the dataframe interchange protocol

What it means

pl.from_dataframe() only accepts objects implementing the dataframe interchange protocol, which it detects by the presence of a __dataframe__ method (pl.DataFrame and Polars interchange wrappers are short-circuited). Anything else — numpy arrays, dicts, lists, frames from libraries without interchange support — raises this TypeError naming the qualified type. Note from_dataframe and the interchange protocol are deprecated since Polars 1.40.0.

Solutions

  1. Use the native constructor for the source type: pl.from_pandas(df), pl.from_arrow(tbl), or pl.from_numpy(arr, schema=...).
  2. For pandas sources, install/upgrade pyarrow (pip install -U pyarrow) and use pandas >= 2.0 so __dataframe__ exists.
  3. For pl.LazyFrame, call .collect() before conversion.
  4. For your own format, implement a __dataframe__ method returning a protocol-conformant object.

Example fix

# before
df = pl.from_dataframe(pandas_df)  # TypeError when __dataframe__ is missing

# after
df = pl.from_pandas(pandas_df)
Defensive patterns

Strategy: type-guard

Validate before calling

if isinstance(df, pl.LazyFrame):
    df = df.collect()
elif not hasattr(df, "__dataframe__"):
    if hasattr(df, "to_arrow"):          # e.g. pyarrow Table
        df = pl.from_arrow(df.to_arrow())
    elif hasattr(df, "columns") and "pandas" in type(df).__module__:
        df = pl.from_pandas(df)
    else:
        raise TypeError(f"cannot convert {type(df).__name__} to Polars")

Type guard

from typing import Any, Protocol, TypeGuard

class SupportsInterchange(Protocol):
    def __dataframe__(self, *, allow_copy: bool = True) -> Any: ...

def supports_interchange(obj: Any) -> TypeGuard[SupportsInterchange]:
    return hasattr(obj, "__dataframe__")

Try / catch

try:
    df = pl.from_dataframe(obj)
except TypeError as e:
    if "does not support the dataframe interchange protocol" not in str(e):
        raise
    df = pl.from_pandas(obj) if "pandas" in type(obj).__module__ else pl.from_arrow(obj)

Prevention

When it happens

Trigger: pl.from_dataframe(obj) where obj is a numpy.ndarray, dict, list, pl.LazyFrame, duckdb relation, or a pandas DataFrame whose interchange support is unavailable (pandas < 1.5, or pyarrow missing on older pandas).

Common situations: Expecting from_dataframe to be a universal converter and passing numpy arrays or dicts; passing a pl.LazyFrame instead of .collect()-ing it; using pandas without pyarrow installed so pandas.DataFrame has no __dataframe__; migrating code after the 1.40 deprecation of the interchange protocol.

Related errors


AI-assisted analysis of pola-rs/polars@9b5d73fd00 (2026-08-19). Data as JSON: /api/errors/036eeae7fba884f2. Report an issue: GitHub.

Appendix: source

Thrown at py-polars/src/polars/interchange/from_dataframe.py:52

        Support for the Dataframe Interchange Protocol is deprecated.

    Parameters
    ----------
    df
        Object supporting the dataframe interchange protocol, i.e. must have implemented
        the `__dataframe__` method.
    allow_copy
        Allow memory to be copied to perform the conversion. If set to False, causes
        conversions that are not zero-copy to fail.
    """
    if isinstance(df, pl.DataFrame):
        return df
    elif isinstance(df, PolarsDataFrame):
        return df._df

    if not hasattr(df, "__dataframe__"):
        msg = f"`df` of type {qualified_type_name(df)!r} does not support the dataframe interchange protocol"
        raise TypeError(msg)

    return _from_dataframe(
        df.__dataframe__(allow_copy=allow_copy),  # type: ignore[arg-type]
        allow_copy=allow_copy,
    )


def _from_dataframe(df: InterchangeDataFrame, *, allow_copy: bool) -> DataFrame:
    chunks = []
    for chunk in df.get_chunks():
        polars_chunk = _protocol_df_chunk_to_polars(chunk, allow_copy=allow_copy)
        chunks.append(polars_chunk)

    # Handle implementations that incorrectly yield no chunks for an empty dataframe
    if not chunks:
        polars_chunk = _protocol_df_chunk_to_polars(df, allow_copy=allow_copy)
        chunks.append(polars_chunk)

View on GitHub (pinned to 9b5d73fd00)