sgl-project/sglang · error · ValueError

`g_cache` must have shape [slots, HV, L, K].

Error message

`g_cache` must have shape [slots, HV, L, K].

What it means

The ReplaySSM gate cache g_cache must be [slots, HV, L, K]: grouped by value heads (num_v_heads), length matching d_cache, and last dim equal to key_dim (the gate shares the key dimension even though it lives on the HV head group). The wrapper validates g_cache.shape[1:] against (num_v_heads, cache_length, key_dim) before kernel selection. A mismatch usually means the gate cache was sized with value_dim or the wrong head count.

Source

Thrown at python/sglang/kernels/ops/attention/helion/kda_replayssm.py:742

        raise ValueError("`write_pos` must be a 1D int32 tensor.")
    if write_pos.shape != (batch,):
        raise ValueError(f"`write_pos` must have shape {(batch,)}.")
    if force_flush is not None and (
        force_flush.ndim != 1
        or force_flush.dtype is not torch.int32
        or force_flush.shape != (batch,)
    ):
        raise ValueError("`force_flush` must be a length-B int32 tensor or None.")

    cache_length = d_cache.size(2)
    if cache_length < 1:
        raise ValueError("ReplaySSM cache length must be at least 1.")
    if d_cache.shape[1:] != (num_v_heads, cache_length, value_dim):
        raise ValueError("`d_cache` must have shape [slots, HV, L, V].")
    if k_cache.shape[1:] != (num_q_heads, cache_length, key_dim):
        raise ValueError("`k_cache` must have shape [slots, H, L, K].")
    if g_cache.shape[1:] != (num_v_heads, cache_length, key_dim):
        raise ValueError("`g_cache` must have shape [slots, HV, L, K].")
    if g_cache.dtype is not torch.float32:
        raise ValueError("`g_cache` must have dtype torch.float32.")

    device = mixed_qkv.device
    if any(
        tensor.device != device for tensor in (d_cache, k_cache, g_cache, write_pos)
    ):
        raise ValueError("ReplaySSM inputs must be on the same device.")
    if force_flush is not None and force_flush.device != device:
        raise ValueError("`force_flush` must be on the same device as the inputs.")

    cache_block = helion.next_power_of_2(max(16, cache_length))
    use_lower_bound = lower_bound is not None
    kernel = _select_replayssm_decode_kernel(
        is_bf16_state=initial_state.dtype is torch.bfloat16,
        num_v_heads=num_v_heads,
    )
    result = kernel(

View on GitHub (pinned to 0132848349)

Solutions

  1. Allocate g_cache as [slots, num_v_heads, cache_length, key_dim] with the same cache_length as d_cache
  2. Double-check the last dim is key_dim (not value_dim) — the gate is per-key-channel decay
  3. Ensure all three caches share the same slots and L; add an assert in your allocation helper

Example fix

# before
g_cache = torch.empty(slots, num_v_heads, cache_len, value_dim, dtype=torch.float32, device='cuda')
# after
g_cache = torch.empty(slots, num_v_heads, cache_len, key_dim, dtype=torch.float32, device='cuda')
Defensive patterns

Strategy: validation

Validate before calling

assert g_cache.shape[1:] == (num_v_heads, d_cache.size(2), key_dim), g_cache.shape

Type guard

def valid_g_cache(t: torch.Tensor, hv: int, k: int, l: int) -> bool:
    return t.ndim == 4 and t.shape[1:] == (hv, l, k)

Prevention

When it happens

Trigger: Calling helion_fused_recurrent_kda_replayssm_decode with g_cache whose shape[1:] != (num_v_heads, d_cache.size(2), key_dim) — e.g. allocated with value_dim as the last dim, or grouped by num_q_heads, or a different cache length than d_cache.

Common situations: Copy-paste allocation of d/k/g caches where g_cache accidentally uses d_cache's dims; hybrid-model state pools whose shape tuple was updated for d but not g; tests exercising the per-row flush contract with hand-built caches.

Related errors


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