{"record":{"id":"599032baca7e42d0","repo":"pola-rs/polars","slug":"string-buffers-must-be-converted","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/column.py","lineNumber":157,"sourceCode":"        else:\n            subchunks_per_chunk = n_chunks // total_n_chunks\n            for chunk in chunks:\n                size = len(chunk)\n                step = size // subchunks_per_chunk\n                if size % subchunks_per_chunk != 0:\n                    step += 1\n                for start in range(0, step * subchunks_per_chunk, step):\n                    yield PolarsColumn(\n                        chunk[start : start + step], allow_copy=self._allow_copy\n                    )\n\n    def get_buffers(self) -> ColumnBuffers:\n        \"\"\"Return a dictionary containing the underlying buffers.\"\"\"\n        dtype = self._col.dtype\n\n        if dtype == String and not self._allow_copy:\n            msg = \"string buffers must be converted\"\n            raise CopyNotAllowedError(msg)\n\n        buffers = self._col._get_buffers()\n\n        return {\n            \"data\": self._wrap_data_buffer(buffers[\"values\"]),\n            \"validity\": self._wrap_validity_buffer(buffers[\"validity\"]),\n            \"offsets\": self._wrap_offsets_buffer(buffers[\"offsets\"]),\n        }\n\n    def _wrap_data_buffer(self, buffer: Series) -> tuple[PolarsBuffer, Dtype]:\n        interchange_buffer = PolarsBuffer(buffer, allow_copy=self._allow_copy)\n        dtype = polars_dtype_to_dtype(buffer.dtype)\n        return interchange_buffer, dtype\n\n    def _wrap_validity_buffer(\n        self, buffer: Series | None\n    ) -> tuple[PolarsBuffer, Dtype] | None:\n        if buffer is None:","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/interchange/column.py#L139-L175","documentation":"Raised by PolarsColumn.get_buffers in the interchange protocol when the column is a String (utf8) dtype and allow_copy=False. Polars' string view layout must be converted to the interchange spec's offsets representation, which requires copying, so the zero-copy contract cannot be honored for strings.","triggerScenarios":"Calling __dataframe__(allow_copy=False) and then get_buffers() on a String column; strict zero-copy consumers (query compilers, arrow-free bridges) walking buffers of a frame that contains string columns; benchmark harnesses asserting no-copy interchange.","commonSituations":"Frames with string keys/labels passed to allow_copy=False consumers; migrating from older polars where string interchange had different copy behavior; performance contracts that forbid copies on hot paths containing text data.","solutions":["Pass allow_copy=True whenever the frame contains String columns","Drop or transform string columns before interchange (e.g. cast to Categorical is not zero-copy either — better to exclude them from the strict path)","If the consumer only needs values, read the interchange column's data via its own iteration APIs rather than raw buffers"],"exampleFix":"// before\ndf.__dataframe__(allow_copy=False).column(0).get_buffers()  # column 0 is String\n// after\ndf.__dataframe__(allow_copy=True).column(0).get_buffers()","handlingStrategy":"validation","validationCode":"string_cols = [name for name, dt in df.schema.items() if dt == pl.String]\nallow_copy = False if not string_cols else True","typeGuard":"def frame_is_zero_copy_safe(df) -> bool:\n    return not any(dt == pl.String for dt in df.schema.values())","tryCatchPattern":"from polars.interchange.protocol import CopyNotAllowedError\ntry:\n    buffers = col.get_buffers()\nexcept CopyNotAllowedError:\n    buffers = PolarsColumn(col._col, allow_copy=True).get_buffers()","preventionTips":["Treat String columns as copy-requiring in the interchange protocol","Split strict zero-copy paths to numeric-only frames"],"tags":["polars","interchange-protocol","string","zero-copy","buffers"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}