inference/research

18 — Reliability: what actually goes wrong in production serving

The decision this document serves: you have a working deployment. What will break, what will degrade silently, and what should you monitor? The gotcha records in this repo are the evidence base — 47 records of things that went wrong in real deployments, found by people who were not looking for them. The ordering below is by what you can detect, not by severity, because the failures you can detect are the ones you can prevent.


1. The one-paragraph version

Production serving failures fall into three categories, and they have different detection profiles:

  1. Silent wrong output — the server starts, serves every request, emits no error, and returns confident wrong text. These are the most dangerous because throughput monitoring does not catch them. Several are faster when broken, so A/B testing selects for the bug.
  2. Silent performance degradation — the server serves correctly but slower. The cause is usually thermal, power-delivery, or clock-state, and it is invisible unless you monitor the specific signal.
  3. Measurement traps — the deployment is fine but the number you are using to make decisions is wrong. These are the most common and the least recognized.

2. Silent wrong output: the failures throughput monitoring cannot catch

2.1 The pattern

Every record in this section shares one property: the server starts, serves every request, emits no error, no warning and no NaN, and returns confident wrong text or wrong logits. The gotcha records are explicit that these were found only because someone ran a cross-check that a deployment would not run.

2.2 The records, grouped by trigger

Quantization + kernel selection:

KV cache + CUDA graphs:

Speculative decoding + attention:

Platform-specific:

2.3 What to monitor

The records are unanimous that none of these are caught by standard health checks. The monitoring that would catch them:

  1. Output quality spot-checks. Run a fixed prompt with a known-good completion at a fixed interval and compare. Draft-model speculative decoding is not lossless at temperature 0 when the target model is quantized records that greedy sampling with spec decode produces different text on a quantized target — so a greedy-decode spot-check is the cheapest oracle.
  2. Kernel selection logs. FlashInfer's b12x MoE backend silently defaults quant_mode to W4A4, so a weight-only NVFP4 checkpoint is computed at the wrong activation precision and compressed-tensors MXFP4 weight-only checkpoints are dispatched to a W4A4 kernel on SM100+, costing ~7.6 average points across AIME/GSM8K/MATH-500 both produce log lines that name the kernel. Alert on any log line that names a W4A4 kernel for a W4A16 checkpoint.
  3. Perplexity regression. A llama.cpp ROCm commit raised WikiText-2 perplexity from 7.72 to 3024 on a Q4_0 model with no error, and only llama-per perplexity caught it records that llama-perplexity on ROCm/gfx1151 returns a PPL jump of two orders of magnitude. Treat a PPL jump of two orders of magnitude as a hard stop.
  4. Cross-backend comparison. On gfx1151 the llama.cpp HIP backend produces corrupt output where Vulkan is correct with byte-identical flags, so cross-backend comparison is the only clean detector was found by running the same model on two backends. A periodic cross-backend comparison on a fixed prompt is the cheapest detector of backend-specific corruption.

3. Silent performance degradation: the failures health checks cannot catch

3.1 Thermal and power-delivery

What to monitor: nvidia-smi throttle-reason codes (SW Power Cap, HW Thermal Slowdown, HW Power Brake), PSU population per node, and p99 latency over a window long enough to contain a real duty cycle — the MLPerf submissions use min_duration 2400000 ms, and Sustained load drives SW Power Cap and thermal throttling, which move the tail of the latency distribution rather than its mean - so a benchmark that reports only p50 hides the regression entirely notes that this node needs roughly 15 minutes to leave its ramp.

3.2 Clock state

What to monitor: lock clocks with nvidia-smi --lock-gpu-clocks=<min>,<max> for any cross-part or cross-run comparison. Never use short-probe TFLOPS as a state verdict.

3.3 Engine and framework regressions

What to monitor: engine version and configuration in the deployment manifest. Any version bump should trigger a re-benchmark and a re-tune of --max-model-len and --max-num-batched-tokens. Enabling the V1 engine shrinks usable context several-fold on the same hardware and model is the clearest example of a version bump silently changing the memory envelope.


4. Measurement traps: the numbers that lie

4.1 Power measurement boundary

What to monitor: always state the measurement boundary alongside any joules-per-token figure. If you must estimate system energy from board power, apply a 1.4-1.7x overhead factor depending on the platform.

4.2 Idle power

What to monitor: utilization, not just throughput. A fleet running at 20% utilization pays 44% of the energy bill for nothing (Modeled US volume-server idle/maximum power dynamic range: 0.44 minimum by 2020 from measured SERT data, 0.28 in the Best Practices scenario, with an explicit ~20-25% idle-power latency floor: idle floor is 0.44 of maximum power for volume servers).

4.3 Carbon intensity


5. The reliability checklist

Before deploying, and at every version bump:

  1. Run a greedy-decode spot-check against a known-good completion. This is the cheapest oracle for silent wrong output (Draft-model speculative decoding is not lossless at temperature 0 when the target model is quantized).
  2. Log the kernel selection and alert on any W4A4 kernel for a W4A16 checkpoint (FlashInfer's b12x MoE backend silently defaults quant_mode to W4A4, so a weight-only NVFP4 checkpoint is computed at the wrong activation precision, compressed-tensors MXFP4 weight-only checkpoints are dispatched to a W4A4 kernel on SM100+, costing ~7.6 average points across AIME/GSM8K/MATH-500).
  3. Monitor throttle-reason codes (nvidia-smi → SW Power Cap, HW Thermal Slowdown, HW Power Brake) and PSU population per node (A DGX H100/H200 node continues to run at REDUCED performance with half its PSUs depopulated - the degradation is silent, not an alert).
  4. Report p99 latency over a 15-minute window, not p50 over a 1-minute window (Sustained load drives SW Power Cap and thermal throttling, which move the tail of the latency distribution rather than its mean - so a benchmark that reports only p50 hides the regression entirely).
  5. Lock clocks for any cross-part comparison (Without locked clocks, cross-part and cross-run comparisons are meaningless - and short bursts measure the parked clock, not the machine).
  6. State the measurement boundary for every joules-per-token figure (GPU board power is 55-59% of system power: CPU, DRAM, NICs, PSU losses and cooling add 41-45% on top, so a joules-per-token figure without its measurement boundary is meaningless).
  7. Re-tune --max-model-len and --max-num-batched-tokens after every engine version bump (Enabling the V1 engine shrinks usable context several-fold on the same hardware and model).
  8. Measure prefix-cache hit rate with and without speculative decoding before enabling spec decode on prefix-heavy workloads (EAGLE/MTP speculative decoding costs 6-10 points of prefix-cache hit rate, and hybrid layouts make the recompute 100x larger).
  9. Set VLLM_ENGINE_READY_TIMEOUT_S=1800 for the first cold start on ROCm (FP8 on RDNA3 blows the 600 s engine-ready timeout on first start even though weights load in seconds).
  10. Do not accept a b12x trace showing an FP4 kernel for a W4A16 checkpoint (FlashInfer's b12x MoE backend silently defaults quant_mode to W4A4, so a weight-only NVFP4 checkpoint is computed at the wrong activation precision).

6. What the records cannot answer

  1. No production-scale reliability study. Every gotcha record is a single report from a single deployment. There is no base rate: the records cannot tell you how likely any of these is in your deployment.
  2. No multi-tenant failure mode. All records are from single-tenant or single-workload deployments. Multi-tenant interference (noisy neighbors, KV cache eviction under memory pressure) is not recorded.
  3. No network failure mode. The records cover GPU, engine, and framework failures but not the network failures (RDMA hangs, InfiniBand congestion, Ethernet packet loss) that dominate multi-node serving reliability.
  4. No persistent-state corruption. All records are from stateless serving. A model that corrupts its own KV cache across requests, or a prefix cache that returns stale entries, would not be caught by any of the monitoring above.

Related documents