[Bugfix][MoE] Snapshot max_cudagraph_capture_size into FusedMoEConfig - #44613
Merged
ywang96 merged 8 commits intoJun 6, 2026
Merged
Conversation
FlashInferExperts, TrtLlmMxfp4ExpertsBase, and the GptOss/Mxfp4 MoE methods read compilation_config.max_cudagraph_capture_size via get_current_vllm_config() in their __init__. process_weights_after_loading re-instantiates these objects, so when it runs outside a set_current_vllm_config() context (e.g. an RL weight reload, or vLLM's own layerwise reload path) the get_current_vllm_config() assertion trips and the reload aborts. Snapshot the value into FusedMoEConfig.max_capture_size at FusedMoE layer construction (always inside the config context, where compilation_config is already in scope) and have the four read sites use moe_config.max_capture_size, removing the global lookup. Mirrors how max_num_tokens is already plumbed in. Co-authored-by: Claude Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: aoshen02 <aoshen@inferact.ai>
aoshen02
requested review from
mgoin,
pavanimajety,
robertgshaw2-redhat,
tlrmchlsmth,
yewentao256 and
zyongye
as code owners
June 5, 2026 04:48
4 tasks
4 tasks
Signed-off-by: aoshen02 <aoshen@inferact.ai>
knight0528
pushed a commit
to knight0528/vllm
that referenced
this pull request
Jun 8, 2026
…vllm-project#44613) Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ekagra-ranjan
pushed a commit
to ekagra-ranjan/vllm
that referenced
this pull request
Jun 9, 2026
…vllm-project#44613) Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Ekagra Ranjan <3116519+ekagra-ranjan@users.noreply.github.com>
waqahmed-amd-fi
pushed a commit
to waqahmed-amd-fi/vllm
that referenced
this pull request
Jun 10, 2026
…vllm-project#44613) Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Waqar Ahmed <waqar.ahmed@amd.com>
Saddss
pushed a commit
to Saddss/vllm
that referenced
this pull request
Jun 14, 2026
…vllm-project#44613) Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6 tasks
divineearthly
pushed a commit
to divineearthly/vllm
that referenced
this pull request
Jun 19, 2026
…vllm-project#44613) Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: divineearthly <divineearthly@gmail.com>
aoshen02
referenced
this pull request
in aoshen02/vllm-detached-backup-20260720
Jun 21, 2026
Add TestWeightReloadCodePaths to test_weight_update.py — exercises the layerwise weight-reload path (initialize → finalize → process_weights_after_loading) across model architecture × quantization combinations using vllm.LLM in-process. Test matrix: - moe-bf16-tiny: TitanML/tiny-mixtral (MoE reload baseline) - moe-bf16-3b: ibm-research/PowerMoE-3b (real MoE kernel reconstruction) - moe-fp8: allenai/OLMoE-1B-7B-0924 with fp8 (#45989 crash path) - moe-mxfp8: allenai/OLMoE-1B-7B-0924 with mxfp8 (#44613 crash path, SM100+) Each case triggers finalize_layerwise_reload which calls process_weights_after_loading on all layers — the exact code path where get_current_vllm_config() crashes during MoE kernel reconstruction if the config context is missing. Verified on GB200 (SM100): 4/4 passed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
nkzhenhua
pushed a commit
to nkzhenhua/vllm
that referenced
this pull request
Jun 24, 2026
…vllm-project#44613) Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ohsono
pushed a commit
to ohsono/vllm
that referenced
this pull request
Jul 3, 2026
…vllm-project#44613) Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dao007forever
pushed a commit
to Dao007forever/vllm
that referenced
this pull request
Jul 18, 2026
…vllm-project#44613) Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
philippesic
pushed a commit
to philippesic/vllm-semantic-cache
that referenced
this pull request
Jul 19, 2026
…vllm-project#44613) Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
plasticchris
pushed a commit
to plasticchris/vllm
that referenced
this pull request
Jul 20, 2026
…vllm-project#44613) Signed-off-by: aoshen02 <aoshen@inferact.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
Several MoE kernels/quant-methods read
get_current_vllm_config().compilation_config.max_cudagraph_capture_sizeinside their
__init__:FlashInferExperts.__init__(fused_moe/experts/flashinfer_cutlass_moe.py)TrtLlmMxfp4ExpertsBase.__init__(fused_moe/experts/trtllm_mxfp4_moe.py)GptOssMxfp4MoEMethod.__init__andMxfp4MoEMethod.__init__(
quantization/mxfp4.py)UnquantizedFusedMoEMethod.process_weights_after_loading(and the mxfp4 methodpaths) re-instantiate these objects every time they run. On the initial
model load that happens inside a
set_current_vllm_config(...)context, so thelookup succeeds. But when
process_weights_after_loadingis invoked againoutside that context — e.g. an RL framework reloading rollout weights, or
vLLM's own layerwise weight-reload path —
get_current_vllm_config()trips itsassertion and the reload aborts:
The FlashInfer CUTLASS unquantized (BF16/FP16) MoE backend is the most visible
case; the same crash reproduces on the mxfp4 paths.
Fix
compilation_config.max_cudagraph_capture_sizeis fixed for the engine'slifetime, so snapshot it once into
FusedMoEConfig.max_capture_sizeatFusedMoElayer-construction time (which always runs inside the configcontext, and where
compilation_configis already in scope), and have the fourread sites use
moe_config.max_capture_size. This removes the implicit globaldependency from kernel/quant-method construction, so rebuilding them during a
weight reload no longer requires an active
set_current_vllm_configcontext.This mirrors how
max_num_tokensis already plumbed from the scheduler configinto
FusedMoEConfig.Test Plan
pre-commit/ ruff check + ruff format on the changed files.tests/kernels/moe/test_flashinfer.py,tests/kernels/moe/test_flashinfer_moe.py,tests/kernels/moe/test_ocp_mx_moe.py,tests/kernels/moe/test_trtllm_nvfp4_moe.py,tests/kernels/moe/test_moe.py.process_weights_after_loading(model, model_config, device)without anactive
set_current_vllm_configcontext (simulating an RL weight reload) andrun a forward pass. Before:
AssertionError: Current vLLM config is not set.After: reload completes and generations match the reloaded weights.
Test Result
Lint:
pre-commit runon the changed files — ruff check, ruff format, mypy,typos, SPDX all pass.
End-to-end RL training run (the original verl#6563 scenario). Reproduced and
fixed in a full verl GRPO run on 8×H200 in the report's image
(
verlai/verl:vllm020.dev1: vLLM 0.20.2, flashinfer 0.6.8.post1). Model: anunquantized MoE (
Qwen3-30B-A3B,qwen3_moe) taking the FlashInfer CUTLASS MoEbackend (
VLLM_USE_FLASHINFER_MOE_FP16=1); VeOmni FSDP actor (ulysses=2, ep=4),vLLM rollout (tp=4). verl syncs updated actor weights into the rollout engine
each step via
update_weights_from_ipc → process_weights_after_loading, whichrebuilds the FlashInfer MoE kernel outside any
set_current_vllm_configcontext. Same script/config on both sides; the only difference is this patch:
AssertionError: Current vLLM config is not set(all TP workers)step:1+ with valid metrics (actor/entropy,rollout_probs_diff_valid=1, throughput)The unpatched crash stack, captured live, is exactly the report's:
Targeted object-level repro. Verified inside the
image from the originating report (
verlai/verl:vllm020.dev1: vLLM 0.20.2,flashinfer 0.6.8.post1) on an H200, which selects the FlashInfer CUTLASS
unquantized MoE backend. The repro builds the exact
FlashInferExperts(moe_config, quant_config)object thatprocess_weights_after_loading → _setup_kernel → make_unquantized_moe_kernelre-instantiates on every weight reload — once insideset_current_vllm_config(...)(initial model load) and once outside it (the RLweight-reload path, e.g. verl
update_weights_from_ipc):AssertionError: Current vLLM config is not set(verbatim from the report)A value-flow check confirmed the kernel sources the value from the config: with
moe_config.max_capture_size = 2048, the kernel read2048outside any context(no global lookup).
Correctness of the snapshot (lifecycle invariance). Snapshotting at build
time is equivalent to the original per-reload global read only if
compilation_config.max_cudagraph_capture_sizeis fixed after startup. Auditedall assignment sites: they live solely in config-construction modules
(
config/compilation.py,config/vllm.py,engine/arg_utils.py,model_executor/models/config.py— all run during engine init, before the modelis built). There are no assignments in any runtime/serving/reload path
(
v1/worker,v1/engine,model_loader,engine), so the value is frozen forthe engine's lifetime and the snapshot matches what the original code read at
every reload. (The pre-existing code re-read this global on every reload even
though it never changes, so it was already effectively a build-time constant.)
Notes
Test/benchmark sites that construct
FusedMoEConfigdirectly do not passmax_capture_sizeand fall back to the default0; the kernels clamp it viamax(self.max_capture_size, 1), and it only feeds the FlashInfer autotuner'stune_max_num_tokenshint, so behavior is unchanged for correctness.AI assistance (Claude Code) was used to investigate and draft this change; the
submitter has reviewed every changed line.