{"record":{"id":"269634cca801ae5e","repo":"pola-rs/polars","slug":"string-buffers-must-be-converted-269634","errorCode":null,"errorMessage":"string buffers must be converted","messagePattern":"string buffers must be converted","errorType":"exception","errorClass":"CopyNotAllowedError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/interchange/from_dataframe.py","lineNumber":111,"sourceCode":") -> Series:\n    buffers = column.get_buffers()\n    offset = column.offset\n\n    data_buffer = _construct_data_buffer(\n        *buffers[\"data\"], column.size(), offset, allow_copy=allow_copy\n    )\n    validity_buffer = _construct_validity_buffer(\n        buffers[\"validity\"], column, dtype, data_buffer, offset, allow_copy=allow_copy\n    )\n    return pl.Series._from_buffers(dtype, data=data_buffer, validity=validity_buffer)\n\n\ndef _string_column_to_series(column: Column, *, allow_copy: bool) -> Series:\n    if column.size() == 0:\n        return pl.Series(dtype=String)\n    elif not allow_copy:\n        msg = \"string buffers must be converted\"\n        raise CopyNotAllowedError(msg)\n\n    buffers = column.get_buffers()\n    offset = column.offset\n\n    offsets_buffer_info = buffers[\"offsets\"]\n    if offsets_buffer_info is None:\n        msg = \"cannot create String column without an offsets buffer\"\n        raise RuntimeError(msg)\n    offsets_buffer = _construct_offsets_buffer(\n        *offsets_buffer_info, offset, allow_copy=allow_copy\n    )\n\n    buffer, dtype = buffers[\"data\"]\n    data_buffer = _construct_data_buffer(\n        buffer, dtype, buffer.bufsize, offset=0, allow_copy=allow_copy\n    )\n\n    # First construct a Series without a validity buffer","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/interchange/from_dataframe.py#L93-L129","documentation":"Raised by _string_column_to_series when converting a non-empty String column with allow_copy=False. The interchange protocol represents strings as separate offsets and data buffers; Polars must repack them into its own binary string layout, and that always allocates. Only an empty string column (size 0) is accepted without copying.","triggerScenarios":"pl.from_dataframe(df, allow_copy=False) where df contains at least one non-empty string column (offsets buffer + UInt8 data buffer).","commonSituations":"Zero-copy pipelines (feature serving, shared-memory handoff, memory-budgeted ingest) that set allow_copy=False globally; consuming from pandas/ibis/cudf/custom producers that expose string data through the interchange protocol.","solutions":["Call pl.from_dataframe(df, allow_copy=True) for data that contains strings","If zero-copy is mandatory, drop or transform string columns upstream before conversion","Wrap the call in try/except CopyNotAllowedError and retry with allow_copy=True so only converting inputs pay the copy"],"exampleFix":"// before\ndf = pl.from_dataframe(producer_df, allow_copy=False)  # CopyNotAllowedError on strings\n\n// after\ntry:\n    df = pl.from_dataframe(producer_df, allow_copy=False)\nexcept pl.exceptions.CopyNotAllowedError:\n    df = pl.from_dataframe(producer_df, allow_copy=True)","handlingStrategy":"try-catch","validationCode":"def has_nonempty_string_column(df) -> bool:\n    proto = df.__dataframe__(allow_copy=False)\n    from polars.interchange.protocol import DtypeKind\n    for col in proto.get_columns():\n        if col.dtype[0] == DtypeKind.STRING and col.size() > 0:\n            return True\n    return False\n\n# if True, expect a copy; pass allow_copy=True directly","typeGuard":null,"tryCatchPattern":"try:\n    out = pl.from_dataframe(df, allow_copy=False)\nexcept pl.exceptions.CopyNotAllowedError:\n    # string layout must be repacked; retry with copies allowed\n    out = pl.from_dataframe(df, allow_copy=True)","preventionTips":["Treat allow_copy=False as a request, not a guarantee: always keep a CopyNotAllowedError fallback path","Do not set allow_copy=False globally for frames known to contain string columns","In zero-copy pipelines, keep string columns in a separate frame converted with allow_copy=True","Log which columns force copies so memory budgets stay predictable"],"tags":["polars","interchange-protocol","zero-copy","memory","string"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}