{"record":{"id":"4f4155556faf2d6b","repo":"jax-ml/jax","slug":"cannot-signal-on-a-non-shaped-semaphore-dst-s","errorCode":null,"errorMessage":"Cannot signal on a non-()-shaped semaphore: {dst_sem_shape}","messagePattern":"Cannot signal on a non-\\(\\)-shaped semaphore: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/pallas/mosaic/primitives.py","lineNumber":360,"sourceCode":"  return []\ndma_start_p.to_lojax = _dma_start_to_lojax\n\n@dma_start_p.def_effectful_abstract_eval\ndef _dma_start_abstract_eval(*args, tree, device_id_type, priority, add):\n  if priority < 0:\n    raise ValueError(f\"DMA start priority must be non-negative: {priority}\")\n  src_ref_aval, dst_ref_aval, dst_sem_aval, src_sem_aval, device_id_aval = (\n      _dma_unflatten(tree, args)\n  )\n  if not all(\n      isinstance(x, (state.AbstractRef, state.TransformedRef))\n      for x in [src_ref_aval, dst_ref_aval, dst_sem_aval]\n  ):\n    raise ValueError(\n        \"DMA source/destination/semaphore arguments must be Refs.\")\n  dst_sem_shape = dst_sem_aval.shape\n  if dst_sem_shape:\n    raise ValueError(\n        f\"Cannot signal on a non-()-shaped semaphore: {dst_sem_shape}\"\n    )\n  if src_sem_aval is not None:\n    if not isinstance(src_sem_aval, (state.AbstractRef, state.TransformedRef)):\n      raise ValueError(\"DMA source semaphore must be a Ref.\")\n    src_sem_shape = src_sem_aval.shape\n    if src_sem_shape:\n      raise ValueError(\n          f\"Cannot signal on a non-()-shaped semaphore: {src_sem_shape}\"\n      )\n  return [], _get_dma_effects(\n      src_ref_aval,\n      dst_ref_aval,\n      dst_sem_aval,\n      src_sem_aval,\n      device_id_aval,\n      device_id_type,\n  )","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/pallas/mosaic/primitives.py#L342-L378","documentation":"DMA completion semaphores are single boolean flags in hardware; signaling requires a scalar ()-shaped semaphore ref. If dst_sem has any non-empty shape the abstract eval rejects it, since there is no per-element signaling.","triggerScenarios":"dma_start where the destination semaphore ref was allocated with a shape, e.g. shape=(1,) or shape=(num_blocks,).","commonSituations":"Allocating a semaphore array for multiple DMAs and passing the whole array instead of one element; mirroring the shape of the buffer being copied onto the semaphore by copy-paste; shape defaults like (1,) instead of ().","solutions":["Allocate the destination semaphore with shape () and pass that scalar ref","If you have an array of semaphores, pass a single element (e.g. sem_ref[i] via slicing that yields a scalar ref)","Use one scalar semaphore per DMA or share one scalar semaphore across DMAs"],"exampleFix":"# before\nsem = alloc_semaphore(shape=(1,))\ndma_start(src, dst, sem)\n\n# after\nsem = alloc_semaphore(shape=())\ndma_start(src, dst, sem)","handlingStrategy":"validation","validationCode":"assert dst_sem.shape == (), f\"semaphore must be scalar, got {dst_sem.shape}\"","typeGuard":"def is_scalar_sem(sem_ref) -> bool:\n  return sem_ref.shape == ()","tryCatchPattern":null,"preventionTips":["Allocate semaphores with shape ()","Slice one element when using semaphore arrays"],"tags":["jax","pallas","mosaic","dma","semaphore","shape-validation"],"backgroundTag":"semaphore-must-be-scalar","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}