{"record":{"id":"f1848a74a10a3b2f","repo":"pola-rs/polars","slug":"copy-not-allowed-cannot-create-structured-array-w","errorCode":null,"errorMessage":"copy not allowed: cannot create structured array without copying data","messagePattern":"copy not allowed: cannot create structured array without copying data","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/dataframe/frame.py","lineNumber":2059,"sourceCode":"\n        Set `structured=True` to convert to a structured array, which can better\n        preserve individual column data such as name and data type.\n\n        >>> df.to_numpy(structured=True)\n        array([(1, 6.5, 'a'), (2, 7. , 'b'), (3, 8.5, 'c')],\n              dtype=[('foo', 'u1'), ('bar', '<f4'), ('ham', '<U1')])\n        \"\"\"  # noqa: W505\n        if use_pyarrow is not None:\n            issue_deprecation_warning(\n                \"the `use_pyarrow` parameter for `DataFrame.to_numpy` is deprecated.\"\n                \" Polars now uses its native engine by default for conversion to NumPy.\",\n                version=\"0.20.28\",\n            )\n\n        if structured:\n            if not allow_copy and not self.is_empty():\n                msg = \"copy not allowed: cannot create structured array without copying data\"\n                raise RuntimeError(msg)\n\n            arrays = []\n            struct_dtype = []\n            for s in self.iter_columns():\n                if s.dtype == Struct:\n                    arr = s.struct.unnest().to_numpy(\n                        structured=True,\n                        allow_copy=True,\n                        use_pyarrow=use_pyarrow,\n                    )\n                else:\n                    arr = s.to_numpy(use_pyarrow=use_pyarrow)\n\n                if s.dtype == String and not s.has_nulls():\n                    arr = arr.astype(str, copy=False)\n                arrays.append(arr)\n                struct_dtype.append((s.name, arr.dtype, arr.shape[1:]))\n","sourceCodeStart":2041,"sourceCodeEnd":2077,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/dataframe/frame.py#L2041-L2077","documentation":"Raised by DataFrame.to_numpy(structured=True, allow_copy=False) on any non-empty frame. A structured (record) numpy array interleaves per-column data into one array of tuples, which fundamentally requires materializing and copying data — there is no zero-copy path from polars' columnar layout. When the caller has forbidden copies (the allow_copy=False zero-copy contract used by the interchange protocol), polars raises RuntimeError instead of silently violating the contract. Empty frames are the one exception and pass through.","triggerScenarios":"`df.to_numpy(structured=True, allow_copy=False)` with `df.height > 0`; dataframe-interchange / `__dataframe__` consumers that request zero-copy and then hit a structured conversion; any pipeline that sets allow_copy=False globally and later requests a record array.","commonSituations":"Building zero-copy interchange adapters (e.g. feeding tools that honor the df interchange protocol); copy-avoidance audits in memory-constrained ETL; converting structured output for libraries that only accept record arrays while enforcing strict no-copy policies.","solutions":["Allow the copy: `df.to_numpy(structured=True, allow_copy=True)`","If copies are unacceptable, take unstructured 2D output `df.to_numpy()` (which can be zero-copy for a single uniform numeric block)","Skip conversion for empty frames explicitly (`if df.is_empty(): ...`) if your code path can hit that","Restructure downstream code to consume columns (arrow/series) instead of record arrays"],"exampleFix":"# before\narr = df.to_numpy(structured=True, allow_copy=False)  # RuntimeError if df non-empty\n\n# after\narr = df.to_numpy(structured=True, allow_copy=True)","handlingStrategy":"validation","validationCode":"structured = True\nallow_copy = False\nif structured and not allow_copy and not df.is_empty():\n    raise RuntimeError('structured conversion requires a copy for non-empty frames')\narr = df.to_numpy(structured=structured, allow_copy=allow_copy)","typeGuard":null,"tryCatchPattern":"try:\n    arr = df.to_numpy(structured=True, allow_copy=False)\nexcept RuntimeError as e:\n    if 'copy not allowed' in str(e):\n        arr = df.to_numpy(structured=True, allow_copy=True)\n    else:\n        raise","preventionTips":["Never request structured=True together with allow_copy=False on data frames","Reserve allow_copy=False for the unstructured 2D numeric path","Document which conversions are zero-copy-safe in your interchange adapters"],"tags":["numpy","structured-array","zero-copy","memory"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}