Skip to content

[Bugfix][MoE] Snapshot max_cudagraph_capture_size into FusedMoEConfig - #44613

Merged
ywang96 merged 8 commits into
vllm-project:mainfrom
aoshen02:fix/moe-snapshot-max-capture-size
Jun 6, 2026
Merged

[Bugfix][MoE] Snapshot max_cudagraph_capture_size into FusedMoEConfig#44613
ywang96 merged 8 commits into
vllm-project:mainfrom
aoshen02:fix/moe-snapshot-max-capture-size

Conversation

@aoshen02

@aoshen02 aoshen02 commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Purpose

Several MoE kernels/quant-methods read
get_current_vllm_config().compilation_config.max_cudagraph_capture_size
inside their __init__:

  • FlashInferExperts.__init__ (fused_moe/experts/flashinfer_cutlass_moe.py)
  • TrtLlmMxfp4ExpertsBase.__init__ (fused_moe/experts/trtllm_mxfp4_moe.py)
  • GptOssMxfp4MoEMethod.__init__ and Mxfp4MoEMethod.__init__
    (quantization/mxfp4.py)

UnquantizedFusedMoEMethod.process_weights_after_loading (and the mxfp4 method
paths) re-instantiate these objects every time they run. On the initial
model load that happens inside a set_current_vllm_config(...) context, so the
lookup succeeds. But when process_weights_after_loading is invoked again
outside that context — e.g. an RL framework reloading rollout weights, or
vLLM's own layerwise weight-reload path — get_current_vllm_config() trips its
assertion and the reload aborts:

AssertionError: Current vLLM config is not set. This typically means
get_current_vllm_config() was called outside of a set_current_vllm_config()
context, or a CustomOp was instantiated at module import time or model forward
time when config is not set.

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_size is fixed for the engine's
lifetime, so snapshot it once into FusedMoEConfig.max_capture_size at
FusedMoE layer-construction time (which always runs inside the config
context, and where compilation_config is already in scope), and have the four
read sites use moe_config.max_capture_size. This removes the implicit global
dependency from kernel/quant-method construction, so rebuilding them during a
weight reload no longer requires an active set_current_vllm_config context.

This mirrors how max_num_tokens is already plumbed from the scheduler config
into FusedMoEConfig.

Test Plan

  • pre-commit / ruff check + ruff format on the changed files.
  • Existing MoE kernel tests:
    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.
  • Repro: load an unquantized FlashInfer-MoE model, then call
    process_weights_after_loading(model, model_config, device) without an
    active set_current_vllm_config context (simulating an RL weight reload) and
    run 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 run on 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: an
unquantized MoE (Qwen3-30B-A3B, qwen3_moe) taking the FlashInfer CUTLASS MoE
backend (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, which
rebuilds the FlashInfer MoE kernel outside any set_current_vllm_config
context. Same script/config on both sides; the only difference is this patch:

run first weight reload (global_step 0) training
unpatched 0.20.2 crashAssertionError: Current vLLM config is not set (all TP workers) dies immediately
with this change reload completes proceeds normally — reaches step:1+ with valid metrics (actor/entropy, rollout_probs_diff_valid=1, throughput)

The unpatched crash stack, captured live, is exactly the report's:

verl/.../vllm_rollout/utils.py:240   update_weights_from_ipc
  process_weights_after_loading(model, model_config, self.device)
vllm/.../model_loader/utils.py:107   process_weights_after_loading
vllm/.../fused_moe/unquantized_fused_moe_method.py:170   _setup_kernel
vllm/.../fused_moe/oracle/unquantized.py:356             make_unquantized_moe_kernel -> experts_cls(...)
vllm/.../fused_moe/flashinfer_cutlass_moe.py:98  __init__
  get_current_vllm_config().compilation_config.max_cudagraph_capture_size
vllm/config/vllm.py:1969  get_current_vllm_config -> AssertionError

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 that process_weights_after_loading → _setup_kernel → make_unquantized_moe_kernel re-instantiates on every weight reload — once inside
set_current_vllm_config(...) (initial model load) and once outside it (the RL
weight-reload path, e.g. verl update_weights_from_ipc):

in-context (initial load) outside context (reload)
unpatched 0.20.2 builds OK AssertionError: Current vLLM config is not set (verbatim from the report)
with this change (backported to 0.20.2) builds OK builds OK — no crash

A value-flow check confirmed the kernel sources the value from the config: with
moe_config.max_capture_size = 2048, the kernel read 2048 outside 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_size is fixed after startup. Audited
all 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 model
is built). There are no assignments in any runtime/serving/reload path
(v1/worker, v1/engine, model_loader, engine), so the value is frozen for
the 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 FusedMoEConfig directly do not pass
max_capture_size and fall back to the default 0; the kernels clamp it via
max(self.max_capture_size, 1), and it only feeds the FlashInfer autotuner's
tune_max_num_tokens hint, 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.

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>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@mergify mergify Bot added nvidia bug Something isn't working labels Jun 5, 2026
@aoshen02 aoshen02 mentioned this pull request Jun 5, 2026
4 tasks
@aoshen02 aoshen02 added the ready ONLY add when PR is ready to merge/full CI is needed label Jun 5, 2026

@zyongye zyongye left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@github-project-automation github-project-automation Bot moved this to Ready in NVIDIA Jun 6, 2026
@ywang96
ywang96 merged commit f87df1d into vllm-project:main Jun 6, 2026
8 of 14 checks passed
@github-project-automation github-project-automation Bot moved this from Ready to Done in NVIDIA Jun 6, 2026
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>
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working nvidia ready ONLY add when PR is ready to merge/full CI is needed

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants