pola-rs/polars · error · CopyNotAllowedError
bitmask must be constructed
Error message
bitmask must be constructed
What it means
When a column declares ColumnNullType.USE_NAN, validity cannot be a zero-copy buffer view: Polars must compute data.is_not_nan(), which allocates a new boolean Series. Because allow_copy=False forbids that allocation, Polars raises CopyNotAllowedError('bitmask must be constructed').
Source
Thrown at py-polars/src/polars/interchange/from_dataframe.py:276
if validity_buffer_info is None:
return None
buffer = validity_buffer_info[0]
return _construct_validity_buffer_from_bitmask(
buffer, null_value, column.size(), offset, allow_copy=allow_copy
)
elif null_type == ColumnNullType.USE_BYTEMASK:
if validity_buffer_info is None:
return None
buffer = validity_buffer_info[0]
return _construct_validity_buffer_from_bytemask(
buffer, null_value, allow_copy=allow_copy
)
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}"View on GitHub (pinned to df599052da)
Solutions
- Retry with allow_copy=True
- Have the producer supply an explicit validity bitmask (USE_BITMASK) instead of NaN semantics
- Materialize validity upstream (replace NaN with real nulls in the producer) before conversion
Example fix
// before
df = pl.from_dataframe(pandas_like_df, allow_copy=False) # NaN nulls -> error
// after
try:
df = pl.from_dataframe(pandas_like_df, allow_copy=False)
except pl.exceptions.CopyNotAllowedError:
df = pl.from_dataframe(pandas_like_df, allow_copy=True) Defensive patterns
Strategy: try-catch
Validate before calling
def columns_use_nan_nulls(df) -> bool:
from polars.interchange.protocol import ColumnNullType
proto = df.__dataframe__(allow_copy=False)
return any(
col.describe_null()[0] == ColumnNullType.USE_NAN
for col in proto.get_columns()
) Try / catch
try:
out = pl.from_dataframe(df, allow_copy=False)
except pl.exceptions.CopyNotAllowedError:
# NaN-derived validity allocates; allow the copy
out = pl.from_dataframe(df, allow_copy=True) Prevention
- Producers: prefer explicit validity bitmasks over NaN semantics for interchange consumers
- Check describe_null() of each column before promising zero-copy behavior
- Keep a single retry-with-copy helper for all CopyNotAllowedError cases in your ingest code
When it happens
Trigger: allow_copy=False conversion of a float column whose producer declares NaN-based nulls (USE_NAN) in describe_null.
Common situations: pandas-like producers that represent missing float values as NaN instead of a validity mask; numeric zero-copy pipelines in ML feature serving.
Related errors
- bitmask must be inverted
- bytemask must be converted into a bitmask
- non-contiguous buffer must be made contiguous
- string buffers must be converted
- functionality for `nan_as_null` has not been implemented and
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/470b61b5b43d1df8.
Report an issue: GitHub.