pola-rs/polars · error · RuntimeError
copy not allowed: cannot create structured array without cop
Error message
copy not allowed: cannot create structured array without copying data
What it means
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.
Source
Thrown at py-polars/src/polars/dataframe/frame.py:2059
Set `structured=True` to convert to a structured array, which can better
preserve individual column data such as name and data type.
>>> df.to_numpy(structured=True)
array([(1, 6.5, 'a'), (2, 7. , 'b'), (3, 8.5, 'c')],
dtype=[('foo', 'u1'), ('bar', '<f4'), ('ham', '<U1')])
""" # noqa: W505
if use_pyarrow is not None:
issue_deprecation_warning(
"the `use_pyarrow` parameter for `DataFrame.to_numpy` is deprecated."
" Polars now uses its native engine by default for conversion to NumPy.",
version="0.20.28",
)
if structured:
if not allow_copy and not self.is_empty():
msg = "copy not allowed: cannot create structured array without copying data"
raise RuntimeError(msg)
arrays = []
struct_dtype = []
for s in self.iter_columns():
if s.dtype == Struct:
arr = s.struct.unnest().to_numpy(
structured=True,
allow_copy=True,
use_pyarrow=use_pyarrow,
)
else:
arr = s.to_numpy(use_pyarrow=use_pyarrow)
if s.dtype == String and not s.has_nulls():
arr = arr.astype(str, copy=False)
arrays.append(arr)
struct_dtype.append((s.name, arr.dtype, arr.shape[1:]))
View on GitHub (pinned to df599052da)
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
Example fix
# before arr = df.to_numpy(structured=True, allow_copy=False) # RuntimeError if df non-empty # after arr = df.to_numpy(structured=True, allow_copy=True)
Defensive patterns
Strategy: validation
Validate before calling
structured = True
allow_copy = False
if structured and not allow_copy and not df.is_empty():
raise RuntimeError('structured conversion requires a copy for non-empty frames')
arr = df.to_numpy(structured=structured, allow_copy=allow_copy) Try / catch
try:
arr = df.to_numpy(structured=True, allow_copy=False)
except RuntimeError as e:
if 'copy not allowed' in str(e):
arr = df.to_numpy(structured=True, allow_copy=True)
else:
raise Prevention
- 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
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- non-contiguous buffer must be made contiguous
- unevenly chunked columns must be rechunked
- string buffers must be converted
- data buffer must be cast from {data_dtype} to UInt32
- byte-packed boolean buffer must be converted to bit-packed b
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/f1848a74a10a3b2f.
Report an issue: GitHub.