{"record":{"id":"693f579470ce65b1","repo":"sgl-project/sglang","slug":"v-pool-shape-must-match-k-pool-shape-got-v-pool","errorCode":null,"errorMessage":"v_pool shape must match k_pool shape, got {v_pool.shape} vs {k_pool.shape}","messagePattern":"v_pool shape must match k_pool shape, got (.+?) vs (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/kernels/aot/python/sgl_kernel/metal.py","lineNumber":92,"sourceCode":"    k_pool_shape = tuple(k_pool.shape)\n    v_pool_shape = tuple(v_pool.shape)\n\n    if q_shape != (q_shape[0], num_qo_heads, head_dim):\n        raise ValueError(\n            \"q shape must be [num_tokens, num_qo_heads, head_dim], \" f\"got {q.shape}\"\n        )\n    if k_shape != (q_shape[0], num_kv_heads, head_dim):\n        raise ValueError(\n            \"k shape must be [num_tokens, num_kv_heads, head_dim], \" f\"got {k.shape}\"\n        )\n    if v_shape != k_shape:\n        raise ValueError(f\"v shape must match k shape, got {v.shape} vs {k.shape}\")\n    if positions_shape != (q_shape[0],) or slots_shape != (q_shape[0],):\n        raise ValueError(\"positions/slots must have one entry per token\")\n    if k_pool_shape[1:] != (num_kv_heads, head_dim):\n        raise ValueError(f\"k_pool has incompatible shape {k_pool.shape}\")\n    if v_pool_shape != k_pool_shape:\n        raise ValueError(\n            f\"v_pool shape must match k_pool shape, got {v_pool.shape} vs {k_pool.shape}\"\n        )\n    if q.dtype != k.dtype or q.dtype != v.dtype:\n        raise ValueError(\"q/k/v dtypes must match\")\n    if k_pool.dtype != q.dtype or v_pool.dtype != q.dtype:\n        raise ValueError(\"pool dtypes must match q/k/v dtype\")\n\n    return _metal.rope_pool_fused(\n        q,\n        k,\n        v,\n        positions,\n        slots,\n        k_pool,\n        v_pool,\n        head_dim,\n        num_qo_heads,\n        num_kv_heads,","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/kernels/aot/python/sgl_kernel/metal.py#L74-L110","documentation":"rope_pool_fused requires v_pool to have exactly the same shape as k_pool ([pool_size, num_kv_heads, head_dim]). This error fires when the V pool's shape (usually pool_size) differs from the K pool, meaning the two halves of the KV cache are inconsistent.","triggerScenarios":"Allocating v_pool with a different pool_size than k_pool (off-by-one or different sizing formula); resizing one pool but not the other; passing pools from different layers/models.","commonSituations":"Cache sizing bug where v_pool uses a different token-capacity formula; memory-pressure code that shrinks only one pool; typos in allocation loops producing mismatched pool sizes.","solutions":["Allocate both pools together with identical shape: torch.empty(pool_size, num_kv_heads, head_dim, dtype) for both k_pool and v_pool","If resizing, resize both: v_pool = v_pool[: k_pool.shape[0]]","Assert v_pool.shape == k_pool.shape at allocation and before the call"],"exampleFix":"# before\nk_pool = torch.empty(pool_size, kv_heads, D)\nv_pool = torch.empty(pool_size - 1, kv_heads, D)  # sizing bug\n\n# after\nk_pool = torch.empty(pool_size, kv_heads, D)\nv_pool = torch.empty(pool_size, kv_heads, D)\nassert v_pool.shape == k_pool.shape","handlingStrategy":"validation","validationCode":"assert v_pool.shape == k_pool.shape, (v_pool.shape, k_pool.shape)","typeGuard":"def pools_match(k_pool, v_pool) -> bool:\n    return k_pool.shape == v_pool.shape","tryCatchPattern":null,"preventionTips":["Allocate K and V pools in one place with identical shapes","Resize both pools together when adjusting capacity"],"tags":["shape-validation","kv-cache","metal","rope","sgl-kernel"],"backgroundTag":"tensor-shape-mismatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}