{"record":{"id":"1ae18d18fa74ab44","repo":"pola-rs/polars","slug":"byte-packed-boolean-buffer-must-be-converted-to-bi","errorCode":null,"errorMessage":"byte-packed boolean buffer must be converted to bit-packed boolean","messagePattern":"byte-packed boolean buffer must be converted to bit-packed boolean","errorType":"exception","errorClass":"CopyNotAllowedError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/interchange/from_dataframe.py","lineNumber":215,"sourceCode":"    *,\n    allow_copy: bool,\n) -> Series:\n    polars_dtype = dtype_to_polars_dtype(dtype)\n\n    # Handle implementations that incorrectly set the data buffer dtype\n    # to the column dtype\n    # https://github.com/pola-rs/polars/pull/10787\n    polars_dtype = polars_dtype_to_data_buffer_dtype(polars_dtype)\n\n    buffer_info = (buffer.ptr, offset, length)\n\n    # Handle byte-packed boolean buffer\n    if polars_dtype == Boolean and dtype[1] == 8:\n        if length == 0:\n            return pl.Series(dtype=Boolean)\n        elif not allow_copy:\n            msg = \"byte-packed boolean buffer must be converted to bit-packed boolean\"\n            raise CopyNotAllowedError(msg)\n        return pl.Series._from_buffer(UInt8, buffer_info, owner=buffer).cast(Boolean)\n\n    return pl.Series._from_buffer(polars_dtype, buffer_info, owner=buffer)\n\n\ndef _construct_offsets_buffer(\n    buffer: Buffer,\n    dtype: Dtype,\n    offset: int,\n    *,\n    allow_copy: bool,\n) -> Series:\n    polars_dtype = dtype_to_polars_dtype(dtype)\n    length = get_buffer_length_in_elements(buffer.bufsize, dtype) - offset\n\n    buffer_info = (buffer.ptr, offset, length)\n    s = pl.Series._from_buffer(polars_dtype, buffer_info, owner=buffer)\n","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/pola-rs/polars/blob/9b5d73fd00236295624374b075d16b1fe6ec6df9/py-polars/src/polars/interchange/from_dataframe.py#L197-L233","documentation":"The interchange protocol allows boolean buffers to be bit-packed (1 bit per value) or byte-packed (8 bits per value, dtype[1] == 8). Polars represents booleans bit-packed, so a byte-packed buffer must be wrapped as UInt8 and cast to Boolean — a copy. With allow_copy=False and a non-empty buffer this raises CopyNotAllowedError; length-0 buffers return an empty Boolean Series.","triggerScenarios":"pl.from_dataframe(obj, allow_copy=False) where a boolean column's dtype tuple has bit width 8 — the natural layout for numpy bool masks and several interchange producers.","commonSituations":"Importing from producers backed by numpy bool arrays; zero-copy pipelines that also carry flag/mask columns; mixed-width boolean handling in custom interop code.","solutions":["Call pl.from_dataframe(obj, allow_copy=True) to permit the UInt8->Boolean cast.","Have the producer bit-pack boolean columns before export.","Catch CopyNotAllowedError and retry with allow_copy=True."],"exampleFix":"# before\ndf = pl.from_dataframe(obj, allow_copy=False)  # byte-packed bool -> CopyNotAllowedError\n\n# after\ndf = pl.from_dataframe(obj, allow_copy=True)","handlingStrategy":"fallback","validationCode":"def has_byte_packed_bools(icdf) -> bool:\n    return any(\n        (c := icdf.get_column(i)).dtype[:2] == (DtypeKind.BOOL, 8) and c.size() > 0\n        for i in range(icdf.num_columns())\n    )\n\nallow_copy = not has_byte_packed_bools(obj.__dataframe__())","typeGuard":null,"tryCatchPattern":"from polars.interchange.protocol import CopyNotAllowedError\n\ntry:\n    df = pl.from_dataframe(obj, allow_copy=False)\nexcept CopyNotAllowedError:\n    df = pl.from_dataframe(obj, allow_copy=True)  # allows UInt8 -> Boolean cast","preventionTips":["Assume numpy-backed producers emit byte-packed booleans.","Bit-pack boolean buffers on the producer if zero-copy transfer is mandatory."],"tags":["polars","interchange-protocol","boolean","bit-packing","allow-copy","copynotallowederror"],"backgroundTag":"copy-not-allowed","analyzedSha":"9b5d73fd00236295624374b075d16b1fe6ec6df9","analyzedAt":"2026-08-19T12:15:06.350Z","contentChangedAt":"2026-08-19T12:15:06.350Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}