{"record":{"id":"dfd6d1883cf31968","repo":"jax-ml/jax","slug":"tuple-of-axes","errorCode":null,"errorMessage":"tuple of axes","messagePattern":"tuple of axes","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"jax/_src/numpy/ufunc_api.py","lineNumber":273,"sourceCode":"      if lax._dtype(where) != bool:\n        raise ValueError(f\"where argument must have dtype=bool; got dtype={lax._dtype(where)}\")\n    reduce = self.__static_props['reduce'] or self._reduce_via_scan\n    return reduce(a, axis=axis, dtype=dtype, keepdims=keepdims, initial=initial, where=where)\n\n  def _reduce_via_scan(self, arr: ArrayLike, axis: int | tuple[int, ...] | None = 0, dtype: DTypeLike | None = None,\n                       keepdims: bool = False, initial: ArrayLike | None = None,\n                       where: ArrayLike | None = None) -> Array:\n    assert self.nin == 2 and self.nout == 1\n    arr = lax.asarray(arr)\n    if initial is None:\n      initial = self.identity\n    if dtype is None:\n      dtype = api.eval_shape(self._func, lax._one(arr), lax._one(arr)).dtype\n    if where is not None:\n      where = _broadcast_to(where, arr.shape)\n    if isinstance(axis, tuple):\n      axis = tuple(canonicalize_axis(a, arr.ndim) for a in axis)\n      raise NotImplementedError(\"tuple of axes\")\n    elif axis is None:\n      if keepdims:\n        final_shape = (1,) * arr.ndim\n      else:\n        final_shape = ()\n      arr = arr.ravel()\n      if where is not None:\n        where = where.ravel()\n      axis = 0\n    else:\n      axis = canonicalize_axis(axis, arr.ndim)\n      if keepdims:\n        final_shape = (*arr.shape[:axis], 1, *arr.shape[axis + 1:])\n      else:\n        final_shape = (*arr.shape[:axis], *arr.shape[axis + 1:])\n\n    # TODO: handle without transpose?\n    if axis != 0:","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/numpy/ufunc_api.py#L255-L291","documentation":"In the scan-based fallback implementation of ufunc.reduce, reducing over a tuple of multiple axes at once is not implemented. Note the raise is unreachable in normal flow (it follows the tuple construction), but tuple-axis reduction on generic ufuncs without a registered reduce is unsupported.","triggerScenarios":"Calling .reduce with axis=(0,1) on a ufunc that lacks a static reduce implementation, falling through to _reduce_via_scan.","commonSituations":"Using exotic ufuncs (only the scan fallback exists) together with multi-axis reduction.","solutions":["Reduce one axis at a time in a loop","Prefer jnp.sum/jnp.prod/jnp.bitwise_or.reduce which have native multi-axis support","Flatten the array first with .reshape(-1) when reducing over all axes"],"exampleFix":"// before\njnp.logical_or.reduce(x, axis=(0,1))\n// after\njnp.logical_or.reduce(x.ravel())","handlingStrategy":"fallback","validationCode":"if isinstance(axis, tuple):\n    for a in axis:\n        x = ufunc.reduce(x, axis=a)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reduce one axis at a time for ufuncs without native reduce support"],"tags":["jax","ufunc","reduce","multi-axis"],"backgroundTag":"unsupported-multi-axis-reduction","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}