Enabling prefix caching kills the engine on the first request when DFlash2
speculative decode is on — at concurrency 1, where the identical binary serves 8/8
with prefix caching off.
engine-fatal: EngineCore busy loop threw: vt: propose_drafts_block: context position
discontinuity (accumulation out of sync with the target's committed positions)
at /src/src/vllm/v1/worker/gpu/runner.cpp:2959
Every subsequent request returns 500 [request submitted to a stopped AsyncLLM]. The
rung reads ok=0 failed=8.
Measured
3d895a202 (PR #2010), sm_121a, artifact-gated: vllm-server 101,151,128 B,
flash_fwd=1792, SpecDecodeFA2Bf16=1. dgx:gpu0 (GB10), idle under an rc lease.
--num-blocks 3744 --max-num-seqs 16 --max-model-len 8192, DFlash2 k=8,
vllm bench serve --dataset-name random --backend openai-chat, 1024 in / 512 out.
| prefix caching |
c=1 |
c=2 |
c=4 |
--no-enable-prefix-caching |
OK 24.84 out tok/s, 8/8 |
OK 40.11, 8/8 |
OK 59.13, 16/16 |
--enable-prefix-caching --scheduling-policy lpm |
VOID, ok=0 failed=8 |
not reached |
not reached |
illegal memory access 0, stream is capturing 0 — this is the position invariant
refusing, not #2028 and not #2029.
Mechanism
With APC on, a request whose prefix is served from cache has its committed positions
begin at the cached prefix length, not at 0. The DFlash2 draft context starts its
accounting at 0 for a new request, so the invariant comparing
step.positions[rows[0]] against the accumulated ctx_len fails on the first
propose. The draft path assumes positions start at zero; prefix caching breaks that
assumption.
Consequence: a shipped SGLang-compat capability is unreachable
ENG-SGLANG-BEHAVIOR-FLAG SW1 exposes --scheduling-policy lpm (SGLang alias
--schedule-policy), cache-aware longest-prefix-match admission ordering. Per
src/vllm/entrypoints/openai/server_main.cpp:1266-1275, lpm needs prefix caching to
have any effect and degrades to fcfs without it. Since prefix caching cannot be
enabled alongside DFlash2, lpm is unreachable in any speculative configuration — the
flag parses, the server boots, and the feature can never do anything. This was its
first-ever load test.
It also means our benchmark's --no-enable-prefix-caching is forced, not a choice,
while the SGLang arm it is compared against runs its radix cache enabled (their flag is
--disable-radix-cache; --disable-radix-attention does not exist upstream and is our
alias only). That asymmetry cannot currently be closed from our side.
Not diagnosed
Whether prefix caching works with speculation OFF is being measured now and will be
posted here; that control separates "APC is broken" from "the APC x DFlash2 interaction
is broken".
Whether the invariant is the DEFECT or the DETECTOR is also open: it may be correctly
refusing a genuinely inconsistent state, in which case the repair is in the draft
context's position accounting, not in the check.
Found while running the first load test of the SW1 lpm path during #2028 ladder work.
Not fixed in flow: it needs its own spec and touches the draft accounting that #2010
just changed.
Enabling prefix caching kills the engine on the first request when DFlash2
speculative decode is on — at concurrency 1, where the identical binary serves 8/8
with prefix caching off.
Every subsequent request returns 500
[request submitted to a stopped AsyncLLM]. Therung reads
ok=0 failed=8.Measured
3d895a202(PR #2010),sm_121a, artifact-gated:vllm-server101,151,128 B,flash_fwd=1792,SpecDecodeFA2Bf16=1. dgx:gpu0 (GB10), idle under anrclease.--num-blocks 3744 --max-num-seqs 16 --max-model-len 8192, DFlash2 k=8,vllm bench serve --dataset-name random --backend openai-chat, 1024 in / 512 out.--no-enable-prefix-caching--enable-prefix-caching --scheduling-policy lpmillegal memory access0,stream is capturing0 — this is the position invariantrefusing, not #2028 and not #2029.
Mechanism
With APC on, a request whose prefix is served from cache has its committed positions
begin at the cached prefix length, not at 0. The DFlash2 draft context starts its
accounting at 0 for a new request, so the invariant comparing
step.positions[rows[0]]against the accumulatedctx_lenfails on the firstpropose. The draft path assumes positions start at zero; prefix caching breaks that
assumption.
Consequence: a shipped SGLang-compat capability is unreachable
ENG-SGLANG-BEHAVIOR-FLAGSW1 exposes--scheduling-policy lpm(SGLang alias--schedule-policy), cache-aware longest-prefix-match admission ordering. Persrc/vllm/entrypoints/openai/server_main.cpp:1266-1275,lpmneeds prefix caching tohave any effect and degrades to
fcfswithout it. Since prefix caching cannot beenabled alongside DFlash2,
lpmis unreachable in any speculative configuration — theflag parses, the server boots, and the feature can never do anything. This was its
first-ever load test.
It also means our benchmark's
--no-enable-prefix-cachingis forced, not a choice,while the SGLang arm it is compared against runs its radix cache enabled (their flag is
--disable-radix-cache;--disable-radix-attentiondoes not exist upstream and is ouralias only). That asymmetry cannot currently be closed from our side.
Not diagnosed
Whether prefix caching works with speculation OFF is being measured now and will be
posted here; that control separates "APC is broken" from "the APC x DFlash2 interaction
is broken".
Whether the invariant is the DEFECT or the DETECTOR is also open: it may be correctly
refusing a genuinely inconsistent state, in which case the repair is in the draft
context's position accounting, not in the check.
Found while running the first load test of the SW1
lpmpath during #2028 ladder work.Not fixed in flow: it needs its own spec and touches the draft accounting that #2010
just changed.