{"record":{"id":"f7eb784141c2e68d","repo":"pola-rs/polars","slug":"only-ufuncs-that-return-one-1d-array-are-supported","errorCode":null,"errorMessage":"only ufuncs that return one 1D array are supported","messagePattern":"only ufuncs that return one 1D array are supported","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/series/series.py","lineNumber":1632,"sourceCode":"                raise RuntimeError(msg)\n\n            arr = arr.__array__(dtype)\n\n        return arr\n\n    def __array_ufunc__(\n        self, ufunc: np.ufunc, method: str_, *inputs: Any, **kwargs: Any\n    ) -> Series:\n        \"\"\"Numpy universal functions.\"\"\"\n        if self._s.n_chunks() > 1:\n            self._s.rechunk(in_place=True)\n\n        s = self._s\n\n        if method == \"__call__\":\n            if ufunc.nout != 1:\n                msg = \"only ufuncs that return one 1D array are supported\"\n                raise NotImplementedError(msg)\n\n            args: list[int | float | np.ndarray[Any, Any]] = []\n            for arg in inputs:\n                if isinstance(arg, (int, float, np.ndarray)):\n                    args.append(arg)\n                elif isinstance(arg, Series):\n                    phys_arg = arg.to_physical()\n                    if phys_arg._s.n_chunks() > 1:\n                        phys_arg._s.rechunk(in_place=True)\n                    args.append(phys_arg._s.to_numpy_view())  # type: ignore[arg-type]\n                else:\n                    msg = f\"unsupported type {qualified_type_name(arg)!r} for {arg!r}\"\n                    raise TypeError(msg)\n\n            # Get minimum dtype needed to be able to cast all input arguments to the\n            # same dtype.\n            dtype_char_minimum: str = np.result_type(*args).char\n","sourceCodeStart":1614,"sourceCodeEnd":1650,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/series/series.py#L1614-L1650","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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()`."],"exampleFix":"// before\nq, r = np.divmod(s, 7)  # NotImplementedError\n\n// after\nq, r = s // 7, s % 7\n# or\nq, r = np.divmod(s.to_numpy(), 7)","handlingStrategy":"type-guard","validationCode":"if getattr(ufunc, 'nout', 1) != 1:\n    result = ufunc(*[a.to_numpy() if isinstance(a, pl.Series) else a for a in args])\nelse:\n    result = ufunc(*args)","typeGuard":"def is_single_output_ufunc(ufunc: np.ufunc) -> bool:\n    return ufunc.nout == 1","tryCatchPattern":"try:\n    q, r = np.divmod(s, k)\nexcept NotImplementedError:\n    q, r = s // k, s % k","preventionTips":["Know the multi-output ufuncs: divmod, modf, frexp - avoid them on Series.","In generic numpy-dispatch wrappers, check ufunc.nout before routing through Series."],"tags":["polars","series","numpy","ufunc","divmod","multi-output"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}