pola-rs/polars · error
only ufuncs that return one 1D array are supported
Error message
only ufuncs that return one 1D array are supported
What it means
Raised in Series.__array_ufunc__ when the numpy ufunc being applied has more than one output array (ufunc.nout != 1). Polars' dispatch only supports single-output elementwise ufuncs, because it routes the computation through a single Rust apply_ufunc_ kernel that must map one input Series to one output Series.
Source
Thrown at py-polars/src/polars/series/series.py:1632
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:
self._s.rechunk(in_place=True)
s = self._s
if method == "__call__":
if ufunc.nout != 1:
msg = "only ufuncs that return one 1D array are supported"
raise NotImplementedError(msg)
args: list[int | float | np.ndarray[Any, Any]] = []
for arg in inputs:
if isinstance(arg, (int, float, np.ndarray)):
args.append(arg)
elif isinstance(arg, Series):
phys_arg = arg.to_physical()
if phys_arg._s.n_chunks() > 1:
phys_arg._s.rechunk(in_place=True)
args.append(phys_arg._s.to_numpy_view()) # type: ignore[arg-type]
else:
msg = f"unsupported type {qualified_type_name(arg)!r} for {arg!r}"
raise TypeError(msg)
# Get minimum dtype needed to be able to cast all input arguments to the
# same dtype.
dtype_char_minimum: str = np.result_type(*args).char
View on GitHub (pinned to df599052da)
Solutions
- Replace with two single-output operations: np.divmod(s, k) -> `(s // k, s % k)`; np.modf(s) -> `(s - s.cast(pl.Float64).floor(), s.floor())`; np.frexp(s) -> use `np.frexp(s.to_numpy())`.
- Detach to numpy when you truly need multi-output: `mantissa, exponent = np.frexp(s.to_numpy())`.
- Check ufunc.nout before generic dispatch in library code: `if ufunc.nout != 1: fall back to to_numpy()`.
Example fix
// before q, r = np.divmod(s, 7) # NotImplementedError // after q, r = s // 7, s % 7 # or q, r = np.divmod(s.to_numpy(), 7)
Defensive patterns
Strategy: type-guard
Validate before calling
if getattr(ufunc, 'nout', 1) != 1:
result = ufunc(*[a.to_numpy() if isinstance(a, pl.Series) else a for a in args])
else:
result = ufunc(*args) Type guard
def is_single_output_ufunc(ufunc: np.ufunc) -> bool:
return ufunc.nout == 1 Try / catch
try:
q, r = np.divmod(s, k)
except NotImplementedError:
q, r = s // k, s % k Prevention
- Know the multi-output ufuncs: divmod, modf, frexp - avoid them on Series.
- In generic numpy-dispatch wrappers, check ufunc.nout before routing through Series.
When it happens
Trigger: `np.divmod(s, 2)` (nout=2), `np.modf(s)` (nout=2), `np.frexp(s)` (nout=2) on a Series. Single-output ufuncs like np.exp/np.add are unaffected; the check fires only for method == '__call__' with multi-output ufuncs.
Common situations: Quotient/remainder computed together via np.divmod; mantissa/exponent splits via np.frexp in signal processing; fractional/int part splits via np.modf - all called on Series inside pandas-style pipelines.
Related errors
- unsupported type {qualified_type_name(arg)!r} for {arg!r}
- could not find `apply_ufunc_{numpy_char_code_to_dtype(dtype_
- only `__call__` is implemented for numpy ufuncs on a Series,
- invalid input for `copy`: {copy!r}
- copy not allowed: cast from {arr.dtype} to {dtype} prohibite
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/f7eb784141c2e68d.
Report an issue: GitHub.