sgl-project/sglang · error · ValueError

group_concurrent_contiguous requires equal-length src/dst in

Error message

group_concurrent_contiguous requires equal-length src/dst index arrays, got {src_indices.size} and {dst_indices.size}

What it means

group_concurrent_contiguous groups src/dst page indices into concurrent contiguous runs for batched KV transfer. It requires src_indices.size == dst_indices.size (both non-empty; empty inputs short-circuit earlier). A length mismatch means the prefill-side page list and decode-side allocation list do not correspond 1:1, which would corrupt the transfer.

Source

Thrown at python/sglang/srt/disaggregation/common/utils.py:123

        dst_addr = dst_aux_ptr + item_len * aux_index
        buffer = (ctypes.c_byte * len(data)).from_address(dst_addr)
        buffer[:] = data
        return


def group_concurrent_contiguous(
    src_indices: npt.NDArray[np.int32], dst_indices: npt.NDArray[np.int32]
) -> Tuple[List[npt.NDArray[np.int32]], List[npt.NDArray[np.int32]]]:
    """Vectorised NumPy implementation."""
    # src/dst indices are transferred pairwise, so an empty side means there is
    # nothing to transfer. Guarding both sides (not just src) avoids a cryptic
    # NumPy broadcast error from np.diff() below when only one side is empty, e.g.
    # a non-empty prefill DSA/SWA state list paired with an empty decode registration.
    if src_indices.size == 0 or dst_indices.size == 0:
        return [], []

    if src_indices.size != dst_indices.size:
        raise ValueError(
            "group_concurrent_contiguous requires equal-length src/dst index arrays, "
            f"got {src_indices.size} and {dst_indices.size}"
        )

    brk = np.where((np.diff(src_indices) != 1) | (np.diff(dst_indices) != 1))[0] + 1
    src_groups = np.split(src_indices, brk)
    dst_groups = np.split(dst_indices, brk)

    src_groups = [g.tolist() for g in src_groups]
    dst_groups = [g.tolist() for g in dst_groups]

    return src_groups, dst_groups


@dataclasses.dataclass(frozen=True)
class DCPTokenTransferPlan:
    src_token_indices: npt.NDArray[np.int64]
    dst_token_indices: npt.NDArray[np.int64]

View on GitHub (pinned to 0132848349)

Solutions

  1. Log both arrays' lengths and content at the call site and reconcile which side is wrong (usually the decode allocation count vs prefill page count)
  2. Ensure prefix/padding math produces identical token->page counts on both servers (same page_size, same padding)
  3. If developing against the helper, pass arrays already validated as equal length

Example fix

# before
group_concurrent_contiguous(src_pages, dst_pages)  # len mismatch -> ValueError
# after
assert src_pages.size == dst_pages.size, (src_pages.size, dst_pages.size)
group_concurrent_contiguous(src_pages, dst_pages)
Defensive patterns

Strategy: validation

Validate before calling

assert src_indices.size == dst_indices.size, (src_indices.size, dst_indices.size)

Type guard

def _valid_index_pair(src: np.ndarray, dst: np.ndarray) -> bool:
    return src.size == dst.size and src.size > 0

Prevention

When it happens

Trigger: Calling send_kvcache / _send_kvcache_generic / send_kvcache_dcp / _send_swa_dsa_state with page-index arrays of different lengths, e.g. prefill computed N pages but decode registration/allocations returned M != N indices.

Common situations: Prefill and decode disagree on prefix length or page count (e.g. chunked prefill boundary off-by-page); decode allocator returned fewer pages for a request; races where one side was updated for an aborted request. Also exercised directly in unit tests of the grouping helper.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/a0f87763ee7f0455. Report an issue: GitHub.