{"record":{"id":"b20ba85bdeaf7dfb","repo":"jax-ml/jax","slug":"ref-must-be-scalar","errorCode":null,"errorMessage":"ref must be scalar.","messagePattern":"ref must be scalar\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/pallas/triton/primitives.py","lineNumber":623,"sourceCode":"    mask: TO BE DOCUMENTED.\n\n  Returns:\n    The value at the given index prior to the atomic operation.\n  \"\"\"\n  return _atomic_rmw(\n      x_ref_or_view, idx, val, mask=mask, atomic_type=AtomicOpType.XOR\n  )\n\n\natomic_cas_p = jax_core.Primitive(\"atomic_cas\")\n\n\n@atomic_cas_p.def_effectful_abstract_eval\ndef _atomic_cas_abstract_eval(ref_aval, cmp_aval, val_aval):\n  if cmp_aval.dtype != val_aval.dtype or cmp_aval.shape != val_aval.shape:\n    raise ValueError(\"cmp and val must have identical dtypes and shapes\")\n  if ref_aval.shape:\n    raise ValueError(\"ref must be scalar.\")\n  if cmp_aval.shape:\n    raise ValueError(\"cmp must be scalar.\")\n  if val_aval.shape:\n    raise ValueError(\"val must be scalar.\")\n  return jax_core.ShapedArray(val_aval.shape, val_aval.dtype), {\n      state.WriteEffect(0)\n  }\n\n\ndef atomic_cas(ref, cmp, val):\n  \"\"\"Performs an atomic compare-and-swap of the value in the ref with the\n\n  given value.\n\n  Args:\n    ref: The ref to operate on.\n    cmp: The expected value to compare against.\n    val: The value to swap in.","sourceCodeStart":605,"sourceCodeEnd":641,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/pallas/triton/primitives.py#L605-L641","documentation":"atomic_cas in Pallas Triton operates on a single scalar memory location, so the Ref passed in must be scalar (shape ()). A Ref with a non-empty shape means an array location was given, which the Triton compare-and-swap lowering cannot handle.","triggerScenarios":"Passing a block Ref or an array-shaped Ref as the first argument to atomic_cas, e.g. p.atomic_cas(block_ref, 0, 1) where block_ref has shape (128,).","commonSituations":"Indexing the Ref first with a scalar index to get a scalar view is forgotten; assuming atomic_cas works elementwise over a whole block like atomic_add with a mask.","solutions":["Index the ref down to a scalar first: p.atomic_cas(ref[idx], cmp, val)","If you need CAS over multiple elements, put it inside a loop over indices with scalar refs"],"exampleFix":"# before\np.atomic_cas(ref, cmp, val)  # ref has shape (8,)\n# after\np.atomic_cas(ref[3], cmp, val)  # scalar location","handlingStrategy":"validation","validationCode":"assert ref_aval.shape == (), 'index the ref down to a scalar before atomic_cas'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass ref[i], not ref, to atomic_cas"],"tags":["jax","pallas","triton","atomic-cas","shape"],"backgroundTag":"invalid-argument-shape","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}