A worker loses its GPU mid-run and the job hangs until a collective times out
When a GPU disappears from its host — a bus fault, a driver reset, a thermal or power event — the rank owning it stops answering. Its peers are inside a collective waiting for data that will never arrive, so the job does not crash at the moment of failure. It stalls, and the first error anyone sees is a timeout on a healthy rank several minutes later.
The rank in the error message is a witness, not the culprit. Take the time of the last progress line and search every node's kernel log at that moment for an accelerator fault.
What this failure is
A stall in which one rank's accelerator becomes unreachable, leaving its peers blocked inside a collective until a timeout fires, so the failure is reported by a healthy rank long after and elsewhere from the fault.
Why it happens (the mechanism)
Collectives have no liveness channel. A rank waiting for data cannot distinguish a peer that is slow from a peer that no longer exists, so it waits for its deadline and then reports what it experienced, which is a timeout. The rank that actually failed lost the device it would have needed to report with, so it says nothing. Every visible piece of evidence therefore comes from the wrong place and the wrong time.
What you'll observe
- The reported error names a rank that is working correctly, not the one that failed
- Minutes pass between the real fault and any log line, so the timestamps mislead
- The job looks alive to the scheduler throughout the stall and keeps its allocation
- Restarting sometimes works, which suggests a transient software fault rather than hardware
Common symptoms and what they mean
| Symptom | Why it happens |
|---|---|
| A fatal timeout arriving several minutes after the last normal progress line | A collective is a rendezvous. Every participant blocks until all of them arrive, and there is no mechanism by which a waiting rank learns that a peer has ceased to exist — it can only observe that the data has not come. The absence of a peer and a peer that is merely slow are indistinguishable until a deadline expires. |
| RuntimeError reporting a worker failed with a device-lost error from the runtime backend | So the failure inverts the usual relationship between cause and report. The rank whose device vanished cannot report anything, because the thing it would report with is gone. The report comes from a healthy rank, describing a symptom of someone else's fault, at a time chosen by the timeout rather than by the event. |
| level_zero backend failed with error 20, UR_RESULT_ERROR_DEVICE_LOST on Intel accelerators | The device loss itself is a host-level event. It is recorded in the kernel log at the instant it happens, which is why that log and the job's own output disagree about when the failure occurred, often by the whole length of the timeout. |
| Xid 79 or a GPU has fallen off the bus message in the host kernel log at the moment progress stopped | A collective is a rendezvous. Every participant blocks until all of them arrive, and there is no mechanism by which a waiting rank learns that a peer has ceased to exist — it can only observe that the data has not come. The absence of a peer and a peer that is merely slow are indistinguishable until a deadline expires. |
| Peer ranks reporting a collective timeout while the failed rank reports nothing at all | So the failure inverts the usual relationship between cause and report. The rank whose device vanished cannot report anything, because the thing it would report with is gone. The report comes from a healthy rank, describing a symptom of someone else's fault, at a time chosen by the timeout rather than by the event. |
Which systems are affected
- Pipeline-parallel and tensor-parallel jobs, where one lost rank stalls every rank downstream of it
- Inference engines that fan a step out to workers and wait on the result
- NVIDIA GPUs raising Xid 79, and Intel accelerators raising a level-zero device-lost result
- Any collective-based workload, since the waiting side is what reports the failure
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.
- ✓Compare the timestamp of the last progress line against the timestamp of the error. A gap matching the configured timeout means the job was stalled, not working, for that interval.
- ✓Search each node's kernel log for an accelerator fault at the time progress stopped; that entry names the failing device directly.
- ✓Determine which rank fell silent first from the per-rank output. That rank, not the one that raised the timeout, is where the fault is.
Example training logs (fingerprint)
RuntimeError: Worker failed with error 'level_zero backend failed with error: 20 (UR_RESULT_ERROR_DEVICE_LOST)'
NVRM: Xid (PCI:0000:41:00): 79, pid=..., GPU has fallen off the bus.
[rank2] Watchdog caught collective operation timeout: WorkNCCL(SeqNum=8412, OpType=ALLREDUCE) 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
Anchoring the investigation to the last progress line rather than the error moves it back to when the fault happened, and the host kernel log at that moment records the device event directly. That converts an unattributable job-level timeout into a named piece of hardware, which is the only form of the problem that can be acted on.
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 |
|---|---|---|
| Timeout reported on one rank | Find the rank that fell silent first | The reporting rank is a witness to someone else's failure. |
| Investigating after the fact | Search host kernel logs at the last-progress timestamp | The device event is recorded when it happens, not when the job notices. |
| Suspected node identified | Drain and test rather than restart onto it | A device lost once is likely to be lost again. |
| Diagnosing actively | Shorten the collective timeout temporarily | Brings the report closer to the event; restore it afterwards. |
With the fix vs without the fix
| Dimension | With the fix | Without the fix |
|---|---|---|
| Which rank the error names | A healthy rank that was waiting | Assumed to be the rank that failed |
| When the error appears | One timeout interval after the fault | Read as the time of the failure |
| What the job does meanwhile | Holds its allocation and looks alive | Expected to crash promptly |
Real engineering notes
“The most expensive mistake here is restarting onto the same pool. A restart usually places ranks differently, so the job survives, the incident is closed, and a device that has already failed once stays in service until it takes down something bigger. Treat a single confirmed device loss as grounds to drain the node, not as a transient to retry through.”
Visual fingerprint
t+0 rank 3 device lost kernel log records it (no job output) t+0 ranks 0,1,2 enter collective and block ... job holds its allocation, scheduler sees it as running t+30m rank 2 watchdog fires -> collective timeout reported HERE visible evidence: rank 2, at t+30m. actual fault: rank 3, at t+0.
Related 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.
The error names rank 2, so why look at rank 3?
Why did nothing fail for half an hour?
A restart fixed it. Was it transient?
Is this the same as a straggler?
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.
Related Reliability errors
Sequence Length Imbalance Causing Distributed Training Stragglers
Reliability · high
Silent Data Corruption from GPU Hardware Faults Causing Loss Spikes and Model Divergence
Reliability · critical
NIXL Firmware Page Registration Fan-Out Triggers Host OOM Kills on HGX H200 and B200
Reliability · critical
MTTF Scaling Inversely with GPU Count in Large ML Research Clusters
Reliability · high