{"record":{"id":"bf4ec83e2abbb8ef","repo":"jax-ml/jax","slug":"only-one-of-src-or-dst-can-be-a-bufferedref","errorCode":null,"errorMessage":"Only one of src or dst can be a BufferedRef.","messagePattern":"Only one of src or dst can be a BufferedRef\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"jax/_src/pallas/mosaic/pipeline.py","lineNumber":1660,"sourceCode":"      core_id * num_iters,\n      core_id * base_num_iters + rem,\n  )\n  offsets = jax_util.tuple_update(\n      (0,) * len(grid),\n      partition_dimension,\n      grid_offset,\n  )\n  return new_grid, offsets\n\n\ndef sync_copy(src: REF | BufferedRef, dst: REF | BufferedRef, indices):\n  \"\"\"Perform a synchronous copy from src to dst.\"\"\"\n  bref: BufferedRef\n  hbm_ref: REF\n  if isinstance(src, BufferedRef):\n    bref = src\n    if isinstance(dst, BufferedRef):\n      raise ValueError(\"Only one of src or dst can be a BufferedRef.\")\n    hbm_ref = dst\n    copy_in = False\n  else:\n    if not isinstance(dst, BufferedRef):\n      raise ValueError(\"One of src or dst must be a BufferedRef.\")\n    bref = dst\n    hbm_ref = src\n    copy_in = True\n  window_ref = bref.current_ref\n  if not bref.is_trivial_windowing:\n    hbm_slice = bref.get_dma_slice(_ref_to_value_aval(hbm_ref), indices)\n    bref_slice = bref._to_window_slice(hbm_slice)\n    hbm_ref = hbm_ref.at[hbm_slice]\n    window_ref = window_ref.at[bref_slice]\n  if copy_in:\n    tpu_helpers.sync_copy(hbm_ref, window_ref)\n  else:\n    tpu_helpers.sync_copy(window_ref, hbm_ref)","sourceCodeStart":1642,"sourceCodeEnd":1678,"githubUrl":"https://github.com/jax-ml/jax/blob/1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb/jax/_src/pallas/mosaic/pipeline.py#L1642-L1678","documentation":"sync_copy copies data between a pipelined BufferedRef and a regular HBM reference. Exactly one side must be the buffered ref; if both src and dst are BufferedRefs, there is no plain memory to copy through, and ValueError 'Only one of src or dst can be a BufferedRef.' is raised.","triggerScenarios":"Calling sync_copy (or a helper like commit / prefetch hooks that route through it) with BufferedRef arguments on both sides, e.g. copying between two pipelined buffers.","commonSituations":"Chaining two pipelined stages and trying to copy buffer-to-buffer directly instead of going through kernel body reads/writes or an intermediate plain Ref.","solutions":["Copy through an intermediate non-buffered Ref (or VMEM scratch) between the two buffered refs","Perform the transfer inside the kernel body by reading from one buffer and writing the other","Restructure so only one spec is pipelined"],"exampleFix":"# before\nsync_copy(in_bref, out_bref)\n# after\nscratch = alloc_buffer(...)  # plain ref\nsync_copy(in_bref, scratch)\nsync_copy(scratch, out_bref)","handlingStrategy":"type-guard","validationCode":"assert not (isinstance(src, BufferedRef) and isinstance(dst, BufferedRef)), \\\n    'sync_copy needs exactly one BufferedRef'","typeGuard":"def exactly_one_bref(src, dst) -> bool:\n    return isinstance(src, BufferedRef) != isinstance(dst, BufferedRef)","tryCatchPattern":null,"preventionTips":["Copy between two buffered refs through an intermediate plain ref or inside the kernel body"],"tags":["jax","pallas","pipeline","copy"],"backgroundTag":"unsupported-operation","analyzedSha":"1e1c6a8fc06dfcd1247076ec5cae4640cea5d7bb","analyzedAt":"2026-08-27T09:53:25.647Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}