AI & Machine Learning Bug Report

vLLM fails to start: max seq len is larger than the tokens the KV cache can store

Serving Llama 3.1 8B with vLLM on a 24 GB GPU crashed at startup with a KV cache error. By default vLLM sizes for the model's full 128k context, and after loading weights there was room for about 45k tokens of KV cache. Setting max_model_len to what we need fixed it.

Ryan Pham Ryan Pham @ryan_bugs · March 26, 2025 · 5 min read · 6 Views
Banner: vLLM startup failure because the configured context length does not fit in the KV cache

We moved an internal summarisation service from a hosted API to self-hosted Llama 3.1 8B Instruct with vLLM on NVIDIA L4 GPUs (24 GB). The container started, loaded weights, profiled memory, and exited:

INFO  Loading model weights took 14.99 GB
INFO  Memory profiling takes 4.21 seconds
INFO  the current vLLM instance can use total_gpu_memory (22.05GiB) x gpu_memory_utilization (0.90) = 19.84GiB
INFO  model weights take 14.99GiB; non_torch_memory takes 0.12GiB; PyTorch activation peak memory takes 1.26GiB; the rest of the memory reserved for KV Cache is 3.47GiB.
...
ValueError: The model's max seq len (131072) is larger than the maximum number of tokens that can be
stored in KV cache (28432). Try increasing `gpu_memory_utilization` or decreasing `max_model_len` when
initializing the engine.

Reproducing it

vllm serve meta-llama/Llama-3.1-8B-Instruct

on any 24 GB GPU reproduces it. The same command worked on an 80 GB A100 in a colleague's test.

What we ruled out

  • Another process using GPU memory. nvidia-smi showed nothing else on the GPU.
  • A broken download or wrong dtype. Weights loaded in bfloat16 as expected, about 15 GB.

Root cause

Unless told otherwise, vLLM sets max_model_len to the model's maximum context, 131,072 tokens for Llama 3.1. It checks at startup that at least one sequence of that length fits in the KV cache. On a 24 GB GPU, after weights and activation memory, only about 3.5 GiB remained for KV cache, enough for roughly 28,000 tokens. Our summaries never needed more than 16,000 tokens of context.

What is happening under the hood

During generation, the model keeps keys and values for every token of every active sequence in every layer. For Llama 3.1 8B:

KV bytes per token = 2 (K and V) x 32 layers x 8 KV heads x 128 head dim x 2 bytes (bf16)
                   = 131,072 bytes = 128 KiB per token

128k tokens for one sequence would need 16 GiB of KV cache, more than the whole GPU has left after weights. vLLM manages KV cache in blocks (PagedAttention) and serves many sequences concurrently from the same pool, so the KV cache size also determines how many requests can run at once.

The knobs:

  • --max-model-len: maximum context per request.
  • --gpu-memory-utilization: fraction of GPU memory vLLM may use (default 0.9).
  • --kv-cache-dtype fp8: halves KV cache memory on supported hardware, with a small quality trade-off.
  • --tensor-parallel-size: splits the model across GPUs, freeing memory per GPU.
  • Quantised weights (AWQ, GPTQ, FP8) free memory for KV cache.

Environment

Component Version / value
Model Llama 3.1 8B Instruct, bf16
Server vLLM 0.8.1, OpenAI-compatible server
GPU NVIDIA L4, 24 GB (22.05 GiB usable)
Host GKE node with one L4
Workload Summaries of documents up to ~12k tokens, outputs up to 1k tokens

Minimal reproduction

docker run --gpus all -p 8000:8000 vllm/vllm-openai:v0.8.1 --model meta-llama/Llama-3.1-8B-Instruct

The fix

Set the context to what the workload needs, with headroom, and check the resulting concurrency:

vllm serve meta-llama/Llama-3.1-8B-Instruct \
  --max-model-len 16384 \
  --gpu-memory-utilization 0.92 \
  --max-num-seqs 32

With 3.6 GiB of KV cache and 128 KiB per token, the pool holds about 29,000 tokens, enough for one 16k request plus several shorter ones at the same time. vLLM logs the maximum concurrency for the configured length at startup, which we now check after every config change.

That concurrency was too low for our peak, so we also tested the FP8 KV cache:

  --kv-cache-dtype fp8

which roughly doubled KV capacity to about 58,000 tokens. Our summarisation eval set (200 documents, rubric-graded) showed no measurable quality difference, so we kept it.

The service also rejects inputs longer than 15,000 tokens before calling vLLM, with a clear error, so a very long document cannot occupy most of the cache.

Alternatives and trade-offs

  • Bigger GPU or two GPUs with tensor parallelism. More KV cache and throughput, at a higher cost per hour.
  • Quantised weights (AWQ or FP8). An 8B model in 4-bit uses about 5 GB, freeing a lot of memory for KV cache; quality impact must be evaluated per task.
  • Raising gpu-memory-utilization close to 1.0. Gains a little, risks out-of-memory errors from CUDA graphs or other allocations.

How to test the fix

Startup succeeds, and a load test with our real document length distribution measured throughput and latency:

config                          max_concurrency  p95 latency  throughput (req/min)
max_len 16k, bf16 KV                 ~1.8x           21 s           38
max_len 16k, fp8 KV                  ~3.6x           14 s           71

Confirming in production

  • The service has run for a month on two L4 nodes, replacing the hosted API for this workload.
  • vLLM's metrics show KV cache usage peaking at about 85 percent at the busiest hour, with no preemptions.

Regression guard

  • The deployment fails health checks if vLLM logs a maximum concurrency below 2.5 at startup.
  • An alert on vllm:num_requests_waiting above 10 for 5 minutes and on KV cache usage above 95 percent.
  • Input length limits enforced at the API layer.

Security implications

Self-hosting moved document contents off a third-party API, which was one of the reasons for the change. The vLLM server has no authentication by default, so it runs on a private network behind our API gateway, and the --api-key option is set as a second layer. The input length limit also protects against a single client exhausting the KV cache.

Prevention checklist

  • Set --max-model-len to what the workload needs, not the model's maximum.
  • Do the KV cache math: bytes per token times tokens needed times concurrency.
  • Check the concurrency vLLM reports at startup.
  • Consider FP8 KV cache or quantised weights, and evaluate quality.
  • Enforce input length limits before the inference server.

References

Add a label

#gpu #vllm #llm-serving #kv-cache #llama
Written by
Ryan Pham @ryan_bugs

I build and run the platforms other engineers ship on: CI/CD pipelines, Kubernetes clusters, GPU inference services, LLM features in production, and the cloud bills that come with all of it. I have also spent years writing and operating automated trading systems, where a rounding bug or a missed websocket message is not a log line but a position you did not intend to hold. Each post here starts from a real failure: the alert, the exact error, what we ruled out, the root cause, and how we proved the fix. Same path every time: Investigate, Explain, Fix, Verify. No hype, no price predictions, just engineering.

Advertisement

Comments

0

No comments yet. Be the first to comment!

Sign In to post a comment.