pola-rs/polars · error · CopyNotAllowedError
bitmask must be constructed
Error message
bitmask must be constructed
What it means
When a column declares USE_NAN nullability (nulls represented by NaN, typical for floats), Polars must compute a validity mask via data.is_not_nan() — a new allocation, not zero-copy. With allow_copy=False this raises CopyNotAllowedError('bitmask must be constructed').
Solutions
- Call pl.from_dataframe(obj, allow_copy=True) so the validity mask can be computed.
- Have the producer export a proper bitmask (USE_BITMAP) validity buffer instead of USE_NAN.
- Catch CopyNotAllowedError and retry with allow_copy=True.
Example fix
# before df = pl.from_dataframe(obj, allow_copy=False) # USE_NAN column -> CopyNotAllowedError # after df = pl.from_dataframe(obj, allow_copy=True) # builds data.is_not_nan() mask
Defensive patterns
Strategy: fallback
Validate before calling
def uses_nan_nulls(icdf) -> bool:
return any(
icdf.get_column(i).describe_null()[0] == ColumnNullType.USE_NAN
for i in range(icdf.num_columns())
)
allow_copy = not uses_nan_nulls(obj.__dataframe__()) Try / catch
from polars.interchange.protocol import CopyNotAllowedError
try:
df = pl.from_dataframe(obj, allow_copy=False)
except CopyNotAllowedError:
df = pl.from_dataframe(obj, allow_copy=True) # allows data.is_not_nan() mask Prevention
- Prefer bitmask validity in producers over NaN-as-null semantics.
- Treat any non-bitmask null representation as copy-requiring when budgeting allocations.
When it happens
Trigger: pl.from_dataframe(obj, allow_copy=False) where describe_null()[0] == ColumnNullType.USE_NAN for some column — producers that conflate NaN and null, or were asked for nan_as_null semantics.
Common situations: Ingesting float columns from producers that mark missing values as NaN; zero-copy pipelines that expect bitmask validity but receive NaN-based validity.
Related errors
- bitmask must be inverted
- bytemask must be converted into a bitmask
- byte-packed boolean buffer must be converted to bit-packed…
- data buffer must be cast from
- offsets buffer must be cast from
AI-assisted analysis of pola-rs/polars@9b5d73fd00 (2026-08-19).
Data as JSON: /api/errors/470b61b5b43d1df8.
Report an issue: GitHub.
Appendix: 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 9b5d73fd00)