{"record":{"id":"bbcc9216c4524f27","repo":"sgl-project/sglang","slug":"combined-history-true-requires-direction-0-bidi","errorCode":null,"errorMessage":"combined_history=True requires direction=0 (bidi)","messagePattern":"combined_history=True requires direction=0 \\(bidi\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/kernels/ops/diffusion/attention/sana_wm_gdn_chunkwise_triton.py","lineNumber":880,"sourceCode":"    kernel never touches — callers must discard the slot they didn't ask for.\n    Reverse scan always seeds from zero (upstream bidi convention: only forward\n    state is cached).\n    \"\"\"\n    BH = I_P_kv.shape[0]\n    _, _, BLOCK_D, _ = A.shape  # A is always full [BH, F, BLOCK_D, BLOCK_D]\n    device, fdtype = I_P_kv.device, torch.float32\n\n    if num_warps is None or num_stages is None or use_acc_fusion is None:\n        _, _, b_w, b_s, b_acc, *_ = _get_arch_config(dot_precision, device=device)\n        if num_warps is None:\n            num_warps = b_w\n        if num_stages is None:\n            num_stages = b_s\n        if use_acc_fusion is None:\n            use_acc_fusion = b_acc\n\n    if combined_history and direction != 0:\n        raise ValueError(\"combined_history=True requires direction=0 (bidi)\")\n\n    # Kernel is DIRECTION-gated (constexpr), so inactive buffers can be 1-element\n    # placeholders — frees ~4× M_fwd-shaped allocs per single-direction call.\n    decay_flat = decay.reshape(BH, F).contiguous().float()\n\n    load_init = init_state_kv is not None\n    dummy = torch.empty(1, device=device, dtype=fdtype)\n\n    def full_M():\n        return torch.empty(BH, F, BLOCK_D, BLOCK_D, device=device, dtype=fdtype)\n\n    def full_z():\n        return torch.empty(BH, F, BLOCK_D, device=device, dtype=fdtype)\n\n    M_fwd = dummy if direction == 2 else full_M()\n    z_fwd = dummy if (direction == 2 or skip_z) else full_z()\n    # Combined-history reuses M_fwd/z_fwd as M_hist/z_hist; rev outputs are\n    # placeholders even though DIRECTION!=1.","sourceCodeStart":862,"sourceCodeEnd":898,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/kernels/ops/diffusion/attention/sana_wm_gdn_chunkwise_triton.py#L862-L898","documentation":"In the chunkwise bidirectional gated-deltanet Triton path, phase_b_triton's combined_history option (writing forward and backward scan history into one buffer) is only implemented for direction=0, the combined bidirectional launch. Passing combined_history=True together with direction=1 or -1 (single-direction passes) is contradictory and rejected.","triggerScenarios":"Calling phase_b_triton(..., combined_history=True, direction=1) — i.e. requesting the combined-history output while running only one scan direction.","commonSituations":"Refactoring fused_bigdn_bidi_chunkwise into separate per-direction calls while keeping the combined_history flag, or copying parameters from the bidi call site into a single-direction invocation.","solutions":["Use combined_history=True only with the default direction=0","For single-direction passes, pass combined_history=False (or None) and use the per-direction history buffers"],"exampleFix":"# before\nphase_b_triton(..., direction=1, combined_history=True)\n# after\nphase_b_triton(..., direction=1, combined_history=False)","handlingStrategy":"validation","validationCode":"assert not (combined_history and direction != 0), 'combined_history requires direction=0'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the combined_history flag tied to the bidi call site only","When splitting into single-direction passes, explicitly set combined_history=False"],"tags":["gdn","linear-attention","triton","argument-validation"],"backgroundTag":"conflicting-arguments","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}