sgl-project/sglang · error · ValueError

num_kv_tokens must fit in the provided source pages, got tok

Error message

num_kv_tokens must fit in the provided source pages, got tokens={num_kv_tokens}, capacity={source_capacity}

What it means

build_dcp_token_transfer_plan computes source_capacity = len(src_pages) * physical_page_size and validates 0 <= num_kv_tokens <= source_capacity (num_kv_tokens defaults to full capacity when None). A token count exceeding the source pages means the plan would read past the allocated prefill KV pages.

Source

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

    dcp_rank: int,
    src_page_offset: int = 0,
    decode_prefix_len: int = 0,
    num_kv_tokens: Optional[int] = None,
) -> DCPTokenTransferPlan:
    virtual_page_size = physical_page_size * dcp_size
    if decode_prefix_len % virtual_page_size != 0:
        raise ValueError(
            "PD DCP transfer requires decode_prefix_len to align to the virtual "
            f"DCP page size ({virtual_page_size}), got {decode_prefix_len}"
        )

    src_pages = np.asarray(src_page_indices, dtype=np.int64)
    dst_pages = np.asarray(dst_page_indices, dtype=np.int64)
    source_capacity = src_pages.size * physical_page_size
    if num_kv_tokens is None:
        num_kv_tokens = source_capacity
    if not 0 <= num_kv_tokens <= source_capacity:
        raise ValueError(
            "num_kv_tokens must fit in the provided source pages, "
            f"got tokens={num_kv_tokens}, capacity={source_capacity}"
        )
    if src_pages.size == 0:
        empty = np.empty((0,), dtype=np.int64)
        return DCPTokenTransferPlan(empty, empty.copy())

    chunk_start = decode_prefix_len + src_page_offset * physical_page_size
    first_owned_offset = (dcp_rank - chunk_start) % dcp_size
    owned_offsets = np.arange(
        first_owned_offset, num_kv_tokens, dcp_size, dtype=np.int64
    )
    src_token_indices = (
        src_pages[owned_offsets // physical_page_size] * physical_page_size
        + owned_offsets % physical_page_size
    )

    relative_positions = src_page_offset * physical_page_size + owned_offsets

View on GitHub (pinned to 0132848349)

Solutions

  1. Recompute num_kv_tokens from the actual src page list: num_kv_tokens = min(desired, len(src_pages) * physical_page_size)
  2. Check that src_page_indices covers the full range you intend to transfer (include pages from all prefill chunks)
  3. If you want 'everything', pass num_kv_tokens=None to use full capacity

Example fix

# before
plan = build_dcp_token_transfer_plan(..., src_page_indices=pages,
    num_kv_tokens=total_seq_len)  # pages only cover a chunk
# after
plan = build_dcp_token_transfer_plan(..., src_page_indices=all_pages,
    num_kv_tokens=min(total_seq_len, all_pages.size * page_size))
Defensive patterns

Strategy: validation

Validate before calling

capacity = src_page_indices.size * physical_page_size
if num_kv_tokens is not None:
    assert 0 <= num_kv_tokens <= capacity, (num_kv_tokens, capacity)

Prevention

When it happens

Trigger: Calling send_kvcache_dcp with num_kv_tokens larger than the provided src_page_indices can hold — e.g. passing the full sequence length while src pages cover only the chunked-prefill portion, or negative token counts.

Common situations: Chunked prefill where num_kv_tokens was computed as total input length but src pages only cover the current chunk; off-by-one in prefix/seq_len arithmetic; passing per-page count instead of token count.

Related errors


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