pola-rs/polars · error · TypeError

invalid sentinel value for column of type {column_dtype}: {n

Error message

invalid sentinel value for column of type {column_dtype}: {null_value!r}

What it means

For USE_SENTINEL null handling, Polars builds pl.Series([null_value]) and, for temporal columns, casts it to the column dtype before comparing with the data. If that cast raises InvalidOperationError, Polars re-raises it as TypeError naming the column dtype and the sentinel value. The producer advertised a sentinel that is not representable in the column's data type.

Source

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

    elif null_type == ColumnNullType.USE_NAN:
        if not allow_copy:
            msg = "bitmask must be constructed"
            raise CopyNotAllowedError(msg)
        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:

View on GitHub (pinned to df599052da)

Solutions

  1. Fix the producer to report a sentinel castable to the column dtype (an in-range integer for temporal types)
  2. If the sentinel must stay as-is, import the column as its raw physical type and reconstruct nulls in Polars manually
  3. Catch TypeError around the conversion and fall back to a manual parsing path
Defensive patterns

Strategy: try-catch

Validate before calling

def sentinel_is_castable(df) -> bool:
    import polars as pl
    from polars.interchange.protocol import ColumnNullType
    proto = df.__dataframe__(allow_copy=False)
    for col in proto.get_columns():
        null_type, null_value = col.describe_null()
        if null_type == ColumnNullType.USE_SENTINEL:
            try:
                pl.Series([null_value])
            except Exception:
                return False
    return True

Try / catch

try:
    out = pl.from_dataframe(df)
except TypeError as e:
    if 'invalid sentinel value' in str(e):
        # producer sentinel metadata is wrong; import raw and fix nulls manually
        out = pl.from_dataframe(df_raw)
    else:
        raise

Prevention

When it happens

Trigger: A temporal column whose describe_null sentinel cannot be cast to that dtype - e.g. a string sentinel for a Datetime/Date column, or an integer sentinel outside the Date value range.

Common situations: Custom producers with mismatched sentinel metadata; porting systems where null markers were stored as strings or out-of-range codes; hand-written __dataframe__ implementations that copy sentinel values from another column type.

Related errors


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