pola-rs/polars · error · CopyNotAllowedError
bitmask must be inverted
Error message
bitmask must be inverted
What it means
For bitmask validity, Polars reads the buffer as a Boolean Series and, when the producer reports null_value != 0 (bits mark nulls instead of valids), must invert it with ~s to obtain a validity mask. The inversion allocates, so under allow_copy=False Polars raises CopyNotAllowedError('bitmask must be inverted').
Source
Thrown at py-polars/src/polars/interchange/from_dataframe.py:312
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
return s
def _construct_validity_buffer_from_bytemask(
buffer: Buffer,
null_value: int,
*,
allow_copy: bool,
) -> Series:
if not allow_copy:
msg = "bytemask must be converted into a bitmask"
raise CopyNotAllowedError(msg)
buffer_info = (buffer.ptr, 0, buffer.bufsize)
s = pl.Series._from_buffer(UInt8, buffer_info, owner=buffer)
s = s.cast(Boolean)View on GitHub (pinned to df599052da)
Solutions
- Retry with allow_copy=True
- Have the producer emit a standard validity mask with null_value=0 (bit set = valid)
- Invert the mask upstream in the producer
Example fix
// before
df = pl.from_dataframe(producer_df, allow_copy=False) # inverted bitmask -> error
// after
try:
df = pl.from_dataframe(producer_df, allow_copy=False)
except pl.exceptions.CopyNotAllowedError:
df = pl.from_dataframe(producer_df, allow_copy=True) Defensive patterns
Strategy: try-catch
Validate before calling
from polars.interchange.protocol import ColumnNullType
def bitmasks_need_inversion(df) -> bool:
proto = df.__dataframe__(allow_copy=False)
return any(
col.describe_null()[:2] == (ColumnNullType.USE_BITMASK, 1)
for col in proto.get_columns()
) Try / catch
try:
out = pl.from_dataframe(df, allow_copy=False)
except pl.exceptions.CopyNotAllowedError:
# inverted bitmask must be flipped; allow the copy
out = pl.from_dataframe(df, allow_copy=True) Prevention
- Producers: emit validity masks (1 = valid, null_value = 0) rather than null-indicator masks
- Verify the reported null_value in describe_null() when zero-copy matters
- Centralize the CopyNotAllowedError retry in one conversion helper
When it happens
Trigger: allow_copy=False conversion of a column with USE_BITMASK validity where describe_null reports null_value=1 (null-indicator mask instead of validity mask).
Common situations: Producers that store null-indicator masks (1 = null) rather than validity masks (1 = valid); zero-copy consumers that assume bitmask validity is always free.
Related errors
- bitmask must be constructed
- bytemask must be converted into a bitmask
- non-contiguous buffer must be made contiguous
- string buffers must be converted
- unevenly chunked columns must be rechunked
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/ba422490df2577b4.
Report an issue: GitHub.