pola-rs/polars · error · RuntimeError

copy not allowed: cast from {arr.dtype} to {dtype} prohibite

Error message

copy not allowed: cast from {arr.dtype} to {dtype} prohibited

What it means

In DataFrame.__array__, when a target dtype was requested that differs from the DataFrame's natural numpy dtype, a cast requires materializing a new array; if the caller set copy=False (allow_copy=False), that cast is prohibited and polars raises RuntimeError rather than silently violating the zero-copy contract. It is a data-integrity guarantee, not a polars bug.

Source

Thrown at py-polars/src/polars/dataframe/frame.py:1030

        https://numpy.org/doc/stable/user/basics.interoperability.html#the-array-method
        """
        if copy is None:
            writable, allow_copy = False, True
        elif copy is True:
            writable, allow_copy = True, True
        elif copy is False:
            writable, allow_copy = False, False
        else:
            msg = f"invalid input for `copy`: {copy!r}"
            raise TypeError(msg)

        arr = self.to_numpy(writable=writable, allow_copy=allow_copy)

        if dtype is not None and dtype != arr.dtype:
            if copy is False:
                # TODO: Only raise when data must be copied
                msg = f"copy not allowed: cast from {arr.dtype} to {dtype} prohibited"
                raise RuntimeError(msg)

            arr = arr.__array__(dtype)

        return arr

    @deprecated(
        "Support for the dataframe interchange protocol is deprecated since version 1.40.0"
    )
    def __dataframe__(
        self,
        nan_as_null: bool = False,  # noqa: FBT001
        allow_copy: bool = True,  # noqa: FBT001
    ) -> PolarsDataFrame:
        """
        Convert to a dataframe object implementing the dataframe interchange protocol.

        .. deprecated:: 1.40.0
            Support for the Dataframe Interchange Protocol is deprecated.

View on GitHub (pinned to df599052da)

Solutions

  1. Drop the dtype argument and cast afterwards only if a copy is acceptable
  2. Relax the constraint: copy=None (default) or copy=True permits the cast
  3. Cast in polars first so the natural numpy dtype already matches: df = df.cast(pl.Float32) then np.array(df, copy=False)
  4. If zero-copy is mandatory, request exactly the DataFrame's native dtype (e.g. df.to_numpy().dtype)

Example fix

# before
np.array(df, copy=False, dtype='float32')

# after
df = df.cast(pl.Float32)
arr = np.array(df, copy=False)
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np

def zero_copy_array(df, dtype=None):
    if dtype is not None and np.dtype(dtype) != df.to_numpy().dtype:
        raise ValueError('cast requested under copy=False; cast the frame first')
    return np.array(df, copy=False)

Try / catch

try:
    arr = np.array(df, copy=False, dtype=dtype)
except RuntimeError as e:
    if 'copy not allowed' in str(e):
        arr = np.array(df, dtype=dtype)  # accept one copy as fallback
    else:
        raise

Prevention

When it happens

Trigger: np.array(df, copy=False, dtype='float32') on an integer or float64 DataFrame; np.array(df, copy=False, dtype=np.int32) against UInt64 data; df.__array__(dtype=..., copy=False) with any lossy or width-changing cast.

Common situations: Zero-copy pipelines (differential-evolution loops, shared-memory IPC) that request dtype normalization while pinning copy=False; consumers assuming NumPy casts are free; downcasting for memory limits with copy constraints carried over from another library.

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/42c4d355cff24533. Report an issue: GitHub.