You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Request hang (silent, zero-log) with hybrid_radix cache + moe-backend offload + nvfp4 triton backend — reproduced on 2 independent models, not explained by #110 #123
A ~2,400-token chat completion request hangs forever (no error, no log
line — not even "Prefill batch") with cache_type='hybrid_radix' + --moe-backend offload + nvfp4_backend='triton', on plenty of free
VRAM. The engine process pins one CPU thread at ~190% while GPU shows
100% utilization at only ~90W (an idle-spin signature, not active
compute), and the frontend never recovers — subsequent requests, even
trivial ones, also hang forever and the process must be kill -9'd.
I initially suspected this was the OOM-crash-then-zombie mechanism from #110, so I tested mitigating it with --memory-ratio (0.9 → 0.8 → 0.5,
raising free-after-init VRAM from 1.82 GiB up to 10.08 GiB — roughly half
the GPU's total free memory). The hang reproduced identically at every
memory-ratio setting, which rules out #110's OOM-driven mechanism as the
cause here (10 GiB free is far beyond any plausible workspace-allocation
OOM for a ~2,400-token prompt). I then reproduced the exact same hang on a second, independent model with the same architecture family
(hybrid attention + mamba/linear-state layers, hybrid_radix cache),
which points at something specific to this cache-type/backend combination
rather than either model's weights.
Resolved config (both models, identical): moe_backend='offload', attention_backend='fi', cache_type='hybrid_radix', nvfp4_backend='triton' (auto-selected — marlin fails at startup with
"donor symbols unavailable" and flashinfer requires sm_120+; triton
is the only usable NVFP4 backend on this sm_89 card)
Deterministic reproduction
Start clean, e.g.:
ft serve --model-path <Qwen3.6-35B-A3B-NVFP4 or Ornith-1.5-35B-A3B-NVFP4 snapshot> \
--max-running-requests 1 --max-seq-len-override 32768 \
--moe-backend offload --moe-cache-size 1024 --port 1920
Startup completes normally, e.g.:
Allocating 712629 tokens for KV cache, K + V = 13.59 GiB
Free memory after initialization: 1.82 GiB
API server is ready to serve on 0.0.0.0:1920
Send a short prompt (~18 tokens) — completes normally, full
"Prefill batch" / "Decode batch" logging, 200 OK.
Send a ~2,400-token Japanese-text prompt (well under the 8,192 max_extend_tokens chunk boundary, so this is a single-chunk prefill):
→ 60s client timeout, 0 bytes received. serve.log gets zero new
lines — not even the "Prefill batch, #new-seq: 1, ..." line that
normally appears the instant a request starts processing.
nvidia-smi during the hang: 100% GPU utilization, but only
~85-91W power draw (idle-spin, not compute — a real prefill/decode on
this model draws much higher). The surviving engine-worker multiprocessing.spawn_main process is pinned at ~150-190% CPU.
The frontend never recovers: a subsequent trivial request (10-token
prompt) also hangs indefinitely and must be killed.
I did not find a clean token-count threshold — in earlier bisection on qwen36-35b-a3b, 1,453/1,622/2,055-token requests all succeeded (2-3s
each) but ~2,400 tokens hung, and removing a single character from the
2,400-token prompt still hung (so it's not an exact-length coincidence
either). The trigger seems to depend on some state beyond raw token count,
not yet isolated.
Not --disable-moe-prefill-overlap — tested, hang identical.
Not multi-chunk prefill — the ~2,400-token repro is a single chunk
(well under max_extend_tokens=8192).
Not --nvfp4-backend choice — only triton runs at all on this GPU
(marlin/flashinfer both fail at startup, unrelated to this bug).
Not model-specific — reproduces identically on two independent
models sharing only the hybrid_radix/mamba-slot architecture family
and moe_backend=offload + nvfp4_backend=triton combination.
What I haven't tried yet
py-spy dump on the hung spawn_main PID (didn't have it installed at
reproduction time; will attach next repro)
--moe-prefill-hit-d2d, or substantially reducing --max-extend-tokens
A non-hybrid (pure-transformer, non-mamba, non-hybrid_radix) MoE model
of similar size, to test whether hybrid_radix cache handling
specifically is implicated
Happy to gather more diagnostics (py-spy, nsys, etc.) if useful — this is
consistently reproducible on my setup.
Summary
A ~2,400-token chat completion request hangs forever (no error, no log
line — not even "Prefill batch") with
cache_type='hybrid_radix'+--moe-backend offload+nvfp4_backend='triton', on plenty of freeVRAM. The engine process pins one CPU thread at ~190% while GPU shows
100% utilization at only ~90W (an idle-spin signature, not active
compute), and the frontend never recovers — subsequent requests, even
trivial ones, also hang forever and the process must be
kill -9'd.I initially suspected this was the OOM-crash-then-zombie mechanism from
#110, so I tested mitigating it with
--memory-ratio(0.9 → 0.8 → 0.5,raising free-after-init VRAM from 1.82 GiB up to 10.08 GiB — roughly half
the GPU's total free memory). The hang reproduced identically at every
memory-ratio setting, which rules out #110's OOM-driven mechanism as the
cause here (10 GiB free is far beyond any plausible workspace-allocation
OOM for a ~2,400-token prompt). I then reproduced the exact same hang on a
second, independent model with the same architecture family
(hybrid attention + mamba/linear-state layers,
hybrid_radixcache),which points at something specific to this cache-type/backend combination
rather than either model's weights.
Environment
0.1.2(PyPI install), torch2.11.0+cu130595.71.05, 2× RTX 4090 24GB (sm_89, no NVLink), onlyCUDA_VISIBLE_DEVICES=0used6.8.0-124-genericnvidia/Qwen3.6-35B-A3B-NVFP4ornith-ai/Ornith-1.5-35B-A3B-NVFP4moe_backend='offload',attention_backend='fi',cache_type='hybrid_radix',nvfp4_backend='triton'(auto-selected —marlinfails at startup with"donor symbols unavailable" and
flashinferrequires sm_120+;tritonis the only usable NVFP4 backend on this sm_89 card)
Deterministic reproduction
"Prefill batch" / "Decode batch" logging, 200 OK.
max_extend_tokenschunk boundary, so this is a single-chunk prefill):serve.loggets zero newlines — not even the "Prefill batch, #new-seq: 1, ..." line that
normally appears the instant a request starts processing.
nvidia-smiduring the hang: 100% GPU utilization, but only~85-91W power draw (idle-spin, not compute — a real prefill/decode on
this model draws much higher). The surviving engine-worker
multiprocessing.spawn_mainprocess is pinned at ~150-190% CPU.prompt) also hangs indefinitely and must be killed.
I did not find a clean token-count threshold — in earlier bisection on
qwen36-35b-a3b, 1,453/1,622/2,055-token requests all succeeded (2-3seach) but ~2,400 tokens hung, and removing a single character from the
2,400-token prompt still hung (so it's not an exact-length coincidence
either). The trigger seems to depend on some state beyond raw token count,
not yet isolated.
What I ruled out
--memory-ratio 0.5raisedfree-after-init VRAM to 10.08 GiB (KV cache shrunk 712K→279,510 tokens)
and the hang still reproduced identically. A genuinely larger request
(~264K target tokens) sent against the same server did process and log
normally (multiple "Prefill batch" lines, increasing token usage %,
~3,000-3,400 tok/s input throughput) before I killed it — so the engine
is not simply incapable of large prefills; something about this
specific mid-size request class triggers total silence instead.
--disable-moe-prefill-overlap— tested, hang identical.(well under
max_extend_tokens=8192).--nvfp4-backendchoice — onlytritonruns at all on this GPU(
marlin/flashinferboth fail at startup, unrelated to this bug).models sharing only the
hybrid_radix/mamba-slot architecture familyand
moe_backend=offload+nvfp4_backend=tritoncombination.What I haven't tried yet
py-spy dumpon the hungspawn_mainPID (didn't have it installed atreproduction time; will attach next repro)
--moe-prefill-hit-d2d, or substantially reducing--max-extend-tokenshybrid_radix) MoE modelof similar size, to test whether
hybrid_radixcache handlingspecifically is implicated
Happy to gather more diagnostics (py-spy, nsys, etc.) if useful — this is
consistently reproducible on my setup.