vLLM returns 500 on every request after the EngineCore process dies
The vLLM V1 API server survives while the separate EngineCore subprocess that owns the model does not. Once that child is gone the server keeps accepting connections and answers every one of them with an internal error until it is restarted, so an outage presents as a healthy-looking process serving nothing.
EngineDeadError names the discovery, not the cause. Read the first worker or engine-core traceback printed ABOVE it, and check dmesg for an out-of-memory kill, which leaves no traceback at all.
What this failure is
An outage mode specific to vLLM's split-process design, in which the model-owning EngineCore subprocess terminates while the HTTP server that fronts it continues running and answering requests with internal errors.
Why it happens (the mechanism)
vLLM V1 puts the model in its own process so the HTTP layer stays responsive. The consequence is that the two can fail independently. When the child dies, the parent finds out only when it next awaits output, and all it can honestly say is that the engine is gone. Nothing in that message distinguishes a missing CUDA kernel from a stalled worker from a subprocess reaped by the kernel, because the parent never saw any of them happen.
What you'll observe
- Every completion request returns HTTP 500 while the container stays up and the port stays open
- A liveness probe that only checks the port keeps the dead instance in the load balancer
- The error the server reports names no cause, so there is nothing obvious to act on
- Restarting clears it for a while and it returns under the same conditions
Common symptoms and what they mean
| Symptom | Why it happens |
|---|---|
| vllm.v1.engine.exceptions.EngineDeadError: EngineCore encountered an issue. See stack trace (above) for the root cause. | EngineDeadError is a bereavement notice, not a diagnosis. The API server process discovers the child is gone when it next awaits output, and reports that discovery. The exception that actually killed the engine was raised inside the EngineCore subprocess and printed to its own stream earlier, which is what the message means by see stack trace above. |
| Engine core proc EngineCore_DP0 died unexpectedly, shutting down client | The child dies for reasons that share nothing but their effect. Reported causes include kernels that do not exist for the device, where a quantized build raises CUDA error no kernel image is available for execution on the device on the first request; an execute_model remote call timing out against a stalled worker; the kernel out-of-memory killer reaping the subprocess under load; and shared-memory limits breaking worker startup. |
| Traceback through output_handler, await engine_core.get_output_async, core_client.py get_output_async | The failure is durable because nothing restarts the engine. The parent has no model of its own to fall back on, so it stays alive serving errors, and a port-based liveness probe cannot tell that apart from a working server. |
| AsyncEngineDeadError: Background loop has errored already on the older V0 engine | EngineDeadError is a bereavement notice, not a diagnosis. The API server process discovers the child is gone when it next awaits output, and reports that discovery. The exception that actually killed the engine was raised inside the EngineCore subprocess and printed to its own stream earlier, which is what the message means by see stack trace above. |
| POST /v1/chat/completions HTTP/1.1 500 Internal Server Error repeating for every subsequent request | The child dies for reasons that share nothing but their effect. Reported causes include kernels that do not exist for the device, where a quantized build raises CUDA error no kernel image is available for execution on the device on the first request; an execute_model remote call timing out against a stalled worker; the kernel out-of-memory killer reaping the subprocess under load; and shared-memory limits breaking worker startup. |
Which systems are affected
- vLLM V1, where the API server and EngineCore are separate processes
- Containers whose health check tests only TCP reachability rather than a real completion
- Deployments using VLLM_WORKER_MULTIPROC_METHOD=spawn
- Any autoscaled fleet, where one dead replica silently absorbs its share of traffic
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.
- ✓Search the log backwards from the EngineDeadError for the first traceback attributed to a worker or engine-core process; that is the cause and it will name a device, a memory limit or a timeout.
- ✓Run dmesg -T | tail and look for an out-of-memory kill naming a Python process at the time of the failure. A kill leaves no application traceback.
- ✓Issue a one-token completion against the instance. If it returns 500 while the port accepts connections, the engine is dead and the process needs restarting rather than investigating live.
Example training logs (fingerprint)
ERROR: Engine core proc EngineCore_DP0 died unexpectedly, shutting down client.
vllm.v1.engine.exceptions.EngineDeadError: EngineCore encountered an issue. See stack trace (above) for the root cause.
INFO: 10.0.4.19:52344 - "POST /v1/chat/completions HTTP/1.1" 500 Internal Server ErrorTimestamps 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
Reading upward finds the exception raised where the failure actually occurred, which names a device, a limit or a timeout and therefore points at a specific change. Replacing the liveness probe fixes the second half of the problem: it converts a permanent silent outage into a restart, so a cause you have not diagnosed yet still stops costing traffic while you diagnose it.
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 |
|---|---|---|
| Dies on the first request | Check kernel support for the device and quantization format | A missing kernel image raises before any load-dependent condition can exist. |
| Dies under sustained load | Check dmesg for an out-of-memory kill, then lower --max-num-seqs | A kernel kill leaves no traceback, so the log alone looks like an unexplained death. |
| Dies during worker startup with tensor parallelism | Raise container shared memory or use host IPC | Worker IPC fails before the engine ever serves a request. |
| Any production deployment | Liveness probe issues a real completion | A port check cannot distinguish a dead engine from a healthy one. |
With the fix vs without the fix
| Dimension | With the fix | Without the fix |
|---|---|---|
| What EngineDeadError tells you | That the child process is gone | Assumed to be the root cause itself |
| Where the real error lives | In the EngineCore or worker output, above the message | Assumed to be absent because the message names no cause |
| Effect of a port-based health check | Dead replica keeps receiving traffic | Assumed the orchestrator will restart it |
Real engineering notes
“The most commonly misdiagnosed variant is the one with no Python traceback anywhere. When the kernel out-of-memory killer reaps the subprocess, there is nothing above the EngineDeadError to read, and the absence of a cause gets reported upstream as a vLLM bug. Check dmesg before opening an issue; host memory pressure from a large tokenizer batch or a co-located process is a frequent culprit and has nothing to do with GPU memory.”
Visual fingerprint
client -> API server process -> EngineCore process -> GPU
(alive) (dead)
| |
| +-- real traceback printed HERE, earlier
+-- EngineDeadError + HTTP 500 printed here, laterRelated 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 says to see the stack trace above, but there is nothing above it.
Why does the server keep returning 500 instead of exiting?
It only happens under load. Is that a vLLM bug?
How do I stop a dead instance from receiving traffic?
References
- ↗vLLM issue #27557: engine core proc EngineCore_DP0 died unexpectedly, shutting down client
- ↗vLLM issue #22414: EngineDeadError deploying GPT-OSS-20B, caused by a missing kernel image
- ↗vLLM issue #17965: TimeoutError on an execute_model RPC preceding the EngineCore failure
- ↗vLLM issue #27194: EngineDeadError during a high-concurrency benchmark
- ↗vLLM troubleshooting guide
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