Mixture-of-experts dispatch and combine collectives time out on large NVLink domains
Expert-parallel routing sends every token to the ranks holding its chosen experts and gathers the results back, an all-to-all exchange whose volume depends on what the router chose. On large NVLink domains this pair of collectives can stop completing, and the job stalls inside it with no rank reporting a fault.
Separate dispatch from combine first, then re-run at a smaller domain size. If it only stalls at full scale, the number of concurrent peer exchanges is the factor rather than the model or the routing.
What this failure is
A stall in the all-to-all exchanges that implement mixture-of-experts routing, in which a dispatch or combine receive never completes on a large NVLink domain and the job halts inside the collective without any rank raising a fault.
Why it happens (the mechanism)
Expert parallelism turns communication into a function of the data. The router decides which ranks exchange how much, so no two steps look alike and the pattern is neither uniform nor symmetric. All-to-all already puts every rank in contact with every other, and a rack-scale domain multiplies those simultaneous contacts, so assumptions that were safe inside one node meet a regime they were never exercised in.
What you'll observe
- The stall is inside a collective, so no rank has an error of its own to report
- It depends on the data, because routing decides the exchange volume, and so it appears irregularly
- It emerges at large domain sizes and cannot be reproduced on a smaller topology
- Both the routing and the transport look correct in isolation
Common symptoms and what they mean
| Symptom | Why it happens |
|---|---|
| A receive operation timing out during the dispatch or combine phase of expert routing | Expert routing makes communication data-dependent. Which ranks exchange how much is decided per step by the router, so the traffic pattern changes from step to step and is not the uniform, symmetric shape that collective implementations are usually tuned and tested against. |
| The stall occurring inside an all-to-all exchange rather than an all-reduce | All-to-all is the most demanding of those patterns because every rank talks to every other simultaneously. Scaling the domain multiplies the number of concurrent peer exchanges rather than adding to it, so resource limits and ordering assumptions that hold within a node can fail across a rack. |
| Onset only at large NVLink domain sizes such as a full rack-scale system | The receive side is where it surfaces because that is the side that waits. A dispatch that was not sent, or was sent to a peer that had already moved on, leaves a receiver blocked with nothing to report except that its data did not arrive. |
| Progress halting mid-step with every rank waiting and none raising a fault | Expert routing makes communication data-dependent. Which ranks exchange how much is decided per step by the router, so the traffic pattern changes from step to step and is not the uniform, symmetric shape that collective implementations are usually tuned and tested against. |
Which systems are affected
- Mixture-of-experts models using expert parallelism, where routing drives an all-to-all
- Rack-scale NVLink domains, where the number of simultaneous peer exchanges is far larger than in a single node
- Low-latency dispatch and combine kernels tuned for such domains
- Any workload whose collective volume is decided by data rather than fixed by shape
How to confirm this is the problem
Apply the following checklist to a small reproduction: each box below is a positive signal that you are looking at this exact failure rather than a sibling in the same taxonomy.
- ✓Determine whether the timing-out operation is the dispatch or the combine exchange; they are separate collectives and only one of them will be at fault.
- ✓Run the same model and data at a smaller domain size. Completing there and stalling at full scale indicates the number of concurrent peer exchanges is the factor.
- ✓Substitute a general-purpose collective for the specialised low-latency path and re-run, which isolates the kernel from the routing.
Example training logs (fingerprint)
dispatch/combine receives time out
[rank17] Watchdog caught collective operation timeout: WorkNCCL(OpType=ALLTOALL) ran for 1800000 milliseconds before timing outTimestamps and exact values vary across runs, but the pattern. An info-level start, an early WARN, an ERROR carrying the symptom. Is the actual fingerprint you should alert on. The Denpex platform flags this combination automatically.
Root cause, fix & prevention, signed in
Sign up free to see why this failure really happens, the exact remediation steps, and the production-grade prevention pattern. You also get 3 free full diagnoses for your own training logs.
Sign up free. Unlock the full analysisNo credit card · 3 free diagnoses · Instant access
Why the recommended fix works
Narrowing to dispatch or combine, and to a domain size, replaces a whole-system symptom with a specific exchange at a specific scale — the only form in which it can be investigated. Falling back to a general-purpose collective separates the specialised kernel from the routing, and capping expert load removes the extreme imbalances that make the exchange hardest.
Code examples
// Typical pattern:
import torch.optim as optim
optimizer = optim.AdamW(model.parameters(), lr=3e-4)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=num_training_steps)
for step in range(num_training_steps):
optimizer.zero_grad()
loss = model(batch)
loss.backward()
optimizer.step()
scheduler.step()Adapt the snippet to your framework. The same pattern holds for PyTorch Lightning, Hugging Face Trainer, DeepSpeed, Megatron-LM, and vLLM training wrappers. Where the wrapper exposes a config flag (for examplelr_scheduler_type in Trainer), prefer the flag over the imperative API to keep the schedule declarative and reproducible.
Best practices by model family
| Model / Stack | Recommendation | Notes |
|---|---|---|
| Stall inside expert routing | Separate dispatch from combine first | They are distinct exchanges; only one will be at fault. |
| Suspected scale dependence | Re-run at a smaller domain size | Completing smaller and stalling larger implicates concurrent peer count. |
| Low-latency kernels in use | Fall back to a general-purpose collective | Isolates the specialised path from the routing logic. |
| Irregular, data-dependent onset | Log the routing distribution per step | Without it an unusual step cannot be correlated with the stall. |
With the fix vs without the fix
| Dimension | With the fix | Without the fix |
|---|---|---|
| What decides the traffic | The router, per step, from the data | Assumed fixed by the model shape |
| Effect of domain size | Multiplies simultaneous peer exchanges | Assumed to add capacity linearly |
| Which side reports | The receiver, which is waiting | Expected from whichever side failed |
Real engineering notes
“The data dependence is what makes this so hard to pin down, and it is worth saying plainly: the same model, the same code and the same hardware will complete thousands of steps and stall on one, because the router produced an unusual distribution on that step. Anyone treating it as a flaky interconnect will chase it indefinitely. Capture the routing distribution per step, or the stall stays unattributable.”
Visual fingerprint
step N router sends rank0 -> {2,5,9} rank1 -> {2} rank2 -> {0,1,...}
step N+1 router sends rank0 -> {3} rank1 -> {3,7,8} rank2 -> {5}
all-to-all: every rank in contact with every other, volumes set by routing
larger domain -> more simultaneous exchanges, not merely more capacityRelated failures to investigate next
Root cause, fix & prevention
Frequently asked questions
Twelve targeted questions that engineers and on-call staff most commonly ask about this failure.
Why does it only happen at full scale?
The same job ran fine a thousand times.
No rank reported an error.
Could this be a hardware fault instead?
Don't just read the fix, diagnose your run
The encyclopedia tells you what went wrong. Denpex tells you what went wrong in YOUR training run. With your logs, your config, and your stack.