sgl-project/sglang · error · ValueError

expected v/g shape {expected_shape}

Error message

expected v/g shape {expected_shape}

What it means

Same dense-layout contract as q/k: the DSpARK KDA MTP kernel requires v and the DSpARK gate g to be [1, T, H, TILE_K] tensors. This check fires when v or g violates that layout (wrong batch dim, token dim, heads, or head dim != 128).

Source

Thrown at python/sglang/kernels/ops/kimi_k3/kda_decode_mtp.py:989

    ReplaySSM: passing the four replayssm_* rings switches the kernel to
    CACHE_RING mode — per-step raw inputs go to the rings (consumed by the
    commit-time exact fold, see kda_replayssm_spec_decode.py) and the per-step
    intermediate_ssm state snapshots are skipped, so intermediate_ssm may be
    None.

    Passing all three onorm_* arguments fuses gated RMSNorm into the recurrence
    kernel.
    """
    import torch

    H = x_q.shape[2]
    N = cu_seqlens.numel() - 1
    T = x_q.shape[1]
    expected_shape = (1, T, H, TILE_K)
    if tuple(x_q.shape) != expected_shape or tuple(x_k.shape) != expected_shape:
        raise ValueError(f"expected q/k shape {expected_shape}")
    if tuple(x_v.shape) != expected_shape or tuple(g.shape) != expected_shape:
        raise ValueError(f"expected v/g shape {expected_shape}")
    if tuple(beta.shape) != (1, T, H):
        raise ValueError(f"expected beta shape {(1, T, H)}")
    # T // N == 1 is num_spec == 0: one token per request, i.e. a plain decode
    # step. The backend never dispatches here for it (that is the dedicated
    # decode kernel's job), but the layout is legal and benchmarks compare the
    # two at this point, so the wrapper accepts it.
    if N <= 0 or T % N != 0 or T // N < 1:
        raise ValueError(
            f"DSpARK KDA MTP requires a fixed 1 + num_spec dense tokens per "
            f"request; got T={T}, N={N}"
        )
    num_spec = T // N - 1
    if recurrent_state.shape[1:] != (H, TILE_K, TILE_K):
        raise ValueError("expected recurrent state layout [pool, H, V=128, K=128]")
    if (
        recurrent_state.dtype != torch.float32
        or tuple(recurrent_state.stride()[-3:]) != (TILE_K * TILE_K, TILE_K, 1)
        or recurrent_state.stride(0) % 4 != 0

View on GitHub (pinned to 0132848349)

Solutions

  1. Reshape both x_v and g to [1, T, H, 128] to match q/k
  2. Check that g (the DSpARK gate) has the same [H, 128] trailing dims as v, not a scalar-per-head layout
  3. Confirm head dim is 128 or use the generic backend

Example fix

# before
v = v.view(T, H, 128); g = g.view(T, H, 128)
fused_kda_decode_mtp_dspark(q, k, v, g, ...)
# after
v = v.view(1, T, H, 128); g = g.view(1, T, H, 128)
fused_kda_decode_mtp_dspark(q, k, v, g, ...)
Defensive patterns

Strategy: validation

Validate before calling

assert x_v.shape == (1, T, H, 128) and g.shape == (1, T, H, 128)

Type guard

def is_dspark_vg(x: torch.Tensor, T: int, H: int) -> bool:
    return tuple(x.shape) == (1, T, H, 128)

Prevention

When it happens

Trigger: Passing x_v or g shaped [T, H, D], [B, T, H, D] with B != 1, or with head dim != 128 to fused_kda_decode_mtp_dspark.

Common situations: Gate tensor g produced with a squeezed/unsqueezed dim compared to v; head_dim-64 model variants; mismatched reshape between q/k path and v/g path in a custom MTP wrapper.

Related errors


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