{"record":{"id":"ea8e0ba3b778dd98","repo":"pola-rs/polars","slug":"unevenly-chunked-columns-must-be-rechunked","errorCode":null,"errorMessage":"unevenly chunked columns must be rechunked","messagePattern":"unevenly chunked columns must be rechunked","errorType":"exception","errorClass":"CopyNotAllowedError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/interchange/dataframe.py","lineNumber":227,"sourceCode":"    def _get_chunks_from_col_chunks(self) -> Iterator[DataFrame]:\n        \"\"\"\n        Return chunks of this dataframe according to the chunks of the first column.\n\n        If columns are not all chunked identically, they will be rechunked like the\n        first column. If copy is not allowed, this raises a RuntimeError.\n        \"\"\"\n        col_chunks = self.get_column(0).get_chunks()\n        chunk_sizes = [chunk.size() for chunk in col_chunks]\n        starts = [0] + list(accumulate(chunk_sizes))\n\n        for i in range(len(starts) - 1):\n            start, end = starts[i : i + 2]\n            chunk = self._df[start:end, :]\n\n            if not all(x == 1 for x in chunk.n_chunks(\"all\")):\n                if not self._allow_copy:\n                    msg = \"unevenly chunked columns must be rechunked\"\n                    raise CopyNotAllowedError(msg)\n                chunk = chunk.rechunk()\n\n            yield chunk\n","sourceCodeStart":209,"sourceCodeEnd":231,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/interchange/dataframe.py#L209-L231","documentation":"Raised inside PolarsDataFrame._get_chunks_from_col_chunks when slicing the frame by column-0 chunk boundaries produces a slice whose columns have uneven chunking, and allow_copy=False. Aligning the columns of each slice requires rechunk (a copy), so the zero-copy contract triggers CopyNotAllowedError.","triggerScenarios":"Calling __dataframe__(allow_copy=False) followed by get_chunks() on a frame whose columns were chunked independently (e.g. after joins, with_columns on multi-chunk frames, hstack of differently-chunked columns); per-column concat or updates leaving misaligned chunk layouts.","commonSituations":"Incrementally built frames (concat/join/update) handed to strict zero-copy interchange consumers; ETL stages that append columns without rechunking; interchange adapters that require allow_copy=False for memory guarantees.","solutions":["Rechunk the frame before interchange: df = df.rechunk()","Pass allow_copy=True so polars may align the chunking","Avoid producing uneven chunk layouts (rechunk after concat/join-heavy construction)"],"exampleFix":"// before\nfor chunk in df.__dataframe__(allow_copy=False).get_chunks():\n    ...\n// after\ndf = df.rechunk()\nfor chunk in df.__dataframe__(allow_copy=False).get_chunks():\n    ...","handlingStrategy":"validation","validationCode":"if not all(n == 1 for n in df.n_chunks('all')):\n    df = df.rechunk()  # required before allow_copy=False chunk iteration","typeGuard":"def is_uniformly_chunked(df) -> bool:\n    sizes = set(df.n_chunks('all'))\n    return len(sizes) <= 1","tryCatchPattern":"from polars.interchange.protocol import CopyNotAllowedError\ntry:\n    for chunk in df.__dataframe__(allow_copy=False).get_chunks():\n        ...\nexcept CopyNotAllowedError:\n    for chunk in df.rechunk().__dataframe__(allow_copy=False).get_chunks():\n        ...","preventionTips":["Rechunk once after concat/join-heavy builds","Keep zero-copy guarantees scoped to frames you constructed and rechunked yourself"],"tags":["polars","interchange-protocol","zero-copy","chunking","memory"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}