{"record":{"id":"91dbaec513eeeb80","repo":"jax-ml/jax","slug":"because-jax-arrays-are-immutable-jnp-ufunc-at-c","errorCode":null,"errorMessage":"Because JAX arrays are immutable, jnp.ufunc.at() cannot operate inplace like\nnp.ufunc.at(). Instead, you can pass inplace=False and capture the result; e.g.\n>>> arr = jnp.add.at(arr, ind, val, inplace=False)\n","messagePattern":"Because JAX arrays are immutable, jnp\\.ufunc\\.at\\(\\) cannot operate inplace like\nnp\\.ufunc\\.at\\(\\)\\. Instead, you can pass inplace=False and capture the result; e\\.g\\.\n>>> arr = jnp\\.add\\.at\\(arr, ind, val, inplace=False\\)\n","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"jax/_src/numpy/ufunc_api.py","lineNumber":442,"sourceCode":"\n    Examples:\n\n      Add numbers to specified indices:\n\n      >>> x = jnp.ones(10, dtype=int)\n      >>> indices = jnp.array([2, 5, 7])\n      >>> values = jnp.array([10, 20, 30])\n      >>> jnp.add.at(x, indices, values, inplace=False)\n      Array([ 1,  1, 11,  1,  1, 21,  1, 31,  1,  1], dtype=int32)\n\n      This is roughly equivalent to JAX's :meth:`jax.numpy.ndarray.at` method\n      called this way:\n\n      >>> x.at[indices].add(values)\n      Array([ 1,  1, 11,  1,  1, 21,  1, 31,  1,  1], dtype=int32)\n    \"\"\"\n    if inplace:\n      raise NotImplementedError(_AT_INPLACE_WARNING)\n\n    at = self.__static_props['at'] or self._at_via_scan\n    return at(a, indices) if b is None else at(a, indices, b)\n\n  def _at_via_scan(self, a: ArrayLike, indices: Any, *args: Any) -> Array:\n    assert len(args) in {0, 1}\n    check_arraylike(f\"{self.__name__}.at\", a, *args)\n    dtype = api.eval_shape(self._func, lax._one(a), *(lax._one(arg) for arg in args)).dtype\n    a = lax.asarray(a).astype(dtype)\n    args = tuple(lax.asarray(arg).astype(dtype) for arg in args)\n    indices = indexing.eliminate_deprecated_list_indexing(indices)\n    if not indices:\n      return a\n\n    shapes = [np.shape(i) for i in indices if not isinstance(i, slice)]\n    shape = shapes and lax.broadcast_shapes(*shapes)\n    if not shape:\n      return a.at[indices].set(self(a.at[indices].get(), *args))","sourceCodeStart":424,"sourceCodeEnd":460,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/numpy/ufunc_api.py#L424-L460","documentation":"Unlike numpy, JAX arrays are immutable, so ufunc.at(..., inplace=True) cannot mutate the input in place. JAX raises NotImplementedError with guidance to use inplace=False and capture the returned updated array.","triggerScenarios":"jnp.add.at(arr, indices, values, inplace=True).","commonSituations":"Porting np.add.at(arr, idx, vals) in-place scatter-add patterns from numpy to JAX.","solutions":["Use inplace=False (or omit it) and reassign: arr = jnp.add.at(arr, ind, val, inplace=False)","Alternatively use arr.at[ind].add(val) which is the idiomatic JAX scatter"],"exampleFix":"// before\njnp.add.at(arr, ind, val, inplace=True)\n// after\narr = jnp.add.at(arr, ind, val, inplace=False)\n# or: arr = arr.at[ind].add(val)","handlingStrategy":"fallback","validationCode":"updated = ufunc.at(a, indices, b, inplace=False)  # never pass inplace=True","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer the idiomatic a.at[indices].add(values) API over ufunc.at","Always reassign the result; JAX never mutates"],"tags":["jax","ufunc","scatter-add","immutable-arrays"],"backgroundTag":"inplace-op-on-immutable-array","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}