pola-rs/polars · error

invalid input for `copy`: {copy!r}

Error message

invalid input for `copy`: {copy!r}

What it means

Raised in Series.__array__ (the numpy array-protocol hook used by np.asarray) when the `copy` argument is anything other than None, True, or False. The protocol contract allows only those three values; anything else - strings like 'never'/'if-needed', integers other than 0/1, custom sentinels - is rejected.

Source

Thrown at py-polars/src/polars/series/series.py:1606

        See Also
        --------
        __array_ufunc__
        """
        # Cast String types to fixed-length string to support string ufuncs
        # TODO: Use variable-length strings instead when NumPy 2.0.0 comes out:
        # https://numpy.org/devdocs/reference/routines.dtypes.html#numpy.dtypes.StringDType
        if dtype is None and not self.has_nulls() and self.dtype == String:
            dtype = np.dtype("U")

        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

    def __array_ufunc__(
        self, ufunc: np.ufunc, method: str_, *inputs: Any, **kwargs: Any
    ) -> Series:
        """Numpy universal functions."""
        if self._s.n_chunks() > 1:

View on GitHub (pinned to df599052da)

Solutions

  1. Pass a supported value: copy=None (allow copy when needed), copy=True (writable copy), copy=False (no copies permitted).
  2. Use the direct API instead of the protocol hook: `s.to_numpy()` / `s.to_numpy(writable=True)`.
  3. If forwarding kwargs, normalize before the call: `copy = {None, True, False}.get(copy, None)` or validate explicitly.

Example fix

// before
np.asarray(s, copy='never')  # TypeError

// after
np.asarray(s, copy=False)
# or
s.to_numpy()
Defensive patterns

Strategy: validation

Validate before calling

assert copy is None or isinstance(copy, bool) or copy in (0, 1), f'invalid copy={copy!r}'
arr = np.asarray(s, copy=copy if isinstance(copy, bool) or copy is None else bool(copy))

Type guard

def valid_copy_param(copy) -> bool:
    return copy is None or isinstance(copy, bool)

Try / catch

try:
    arr = np.asarray(s, copy=copy)
except TypeError as e:
    if 'invalid input for `copy`' not in str(e):
        raise
    arr = s.to_numpy()

Prevention

When it happens

Trigger: `np.asarray(s, copy='never')`, `s.__array__(copy='if-needed')`, `np.asarray(s, copy=2)`, or code passing a numpy-1.x `np.copy` style constant. Only the three canonical values map to (writable, allow_copy) tuples; everything else falls into the raise.

Common situations: Code written for libraries with richer copy semantics (CuPy uses copy='never'/'if-needed' strings); mechanical migration of np.array(...) calls where copy had legacy meanings; kwargs forwarded from another function with an unexpected value.

Related errors


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