pola-rs/polars · error · NotImplementedError

unsupported null type

Error message

unsupported null type: {null_type!r}

What it means

Polars' interchange importer understands exactly four null representations: USE_BITMAP, USE_BYTEMASK, USE_NAN, and USE_SENTINEL. If a column's describe_null() reports any other ColumnNullType (including None or constants from newer protocol revisions), NotImplementedError('unsupported null type: ...') is raised.

Solutions

  1. Upgrade Polars to a version that knows the null type.
  2. Fix the producer to report one of USE_BITMAP/USE_BYTEMASK/USE_NAN/USE_SENTINEL (or no nulls at all).
  3. Convert via pyarrow or the producer's native export path instead of the interchange protocol.

Example fix

# producer side, before
 def describe_null(self):
     return (None, None)  # -> NotImplementedError
# after
 def describe_null(self):
     return (ColumnNullType.USE_BITMAP, 0)
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED_NULL_TYPES = {
    ColumnNullType.USE_BITMAP,
    ColumnNullType.USE_BYTEMASK,
    ColumnNullType.USE_NAN,
    ColumnNullType.USE_SENTINEL,
}

unsupported = [
    i for i in range(icdf.num_columns())
    if icdf.get_column(i).describe_null()[0] not in SUPPORTED_NULL_TYPES
]

Try / catch

try:
    df = pl.from_dataframe(obj)
except NotImplementedError as e:
    if "unsupported null type" not in str(e):
        raise
    # upgrade Polars, or fix the producer's describe_null() to a supported constant

Prevention

When it happens

Trigger: pl.from_dataframe(obj) where describe_null()[0] is outside the four supported values — a buggy producer returning None/0, or a producer built against a newer protocol revision that added a null type this Polars version does not know.

Common situations: Version skew: producer library newer than the installed Polars; custom interchange implementations returning a placeholder; producers using the protocol's NONNULL constant incorrectly (it must be handled before buffers are requested).

Related errors


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

Appendix: source

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

        return data.is_not_nan()

    elif null_type == ColumnNullType.USE_SENTINEL:
        if not allow_copy:
            msg = "bitmask must be constructed"
            raise CopyNotAllowedError(msg)

        sentinel = pl.Series([null_value])
        try:
            if column_dtype.is_temporal():
                sentinel = sentinel.cast(column_dtype)
            return data != sentinel  # noqa: TRY300
        except InvalidOperationError as e:
            msg = f"invalid sentinel value for column of type {column_dtype}: {null_value!r}"
            raise TypeError(msg) from e

    else:
        msg = f"unsupported null type: {null_type!r}"
        raise NotImplementedError(msg)


def _construct_validity_buffer_from_bitmask(
    buffer: Buffer,
    null_value: int,
    length: int,
    offset: int = 0,
    *,
    allow_copy: bool,
) -> Series:
    buffer_info = (buffer.ptr, offset, length)
    s = pl.Series._from_buffer(Boolean, buffer_info, buffer)

    if null_value != 0:
        if not allow_copy:
            msg = "bitmask must be inverted"
            raise CopyNotAllowedError(msg)
        s = ~s

View on GitHub (pinned to 9b5d73fd00)