The vLLM server fails on large max-num-batched-tokens

When specifying large number in max-num-batched-tokens the server fails instead of limiting the concurrency (num scheduled). From the log it seems it can get the CUDA available memory and use it to cap - a much better behavior. I used max-num-batched-tokens to limit concurrency in profiling experiments, and above some limit it fails instead of limiting the concurrency.

==========================================================

INFO 09-13 13:31:13 [init.py:235] Automatically detected platform cuda.
INFO 09-13 13:31:16 [api_server.py:1755] vLLM API server version 0.10.1.dev1+gbcc0a3cbe
INFO 09-13 13:31:16 [cli_args.py:261] non-default args: {‘model_tag’: ‘mistralai/Mistral-7B-Instruct-v0.2’, ‘host’: ‘0.0.0.0’, ‘model’: ‘mistralai/Mistral-7B-Instruct-v0.2’, ‘trust_remote_code’: True, ‘max_model_len’: 16384, ‘block_size’: 32, ‘enable_prefix_caching’: False, ‘max_num_batched_tokens’: 200000, ‘max_num_seqs’: 200, ‘enable_chunked_prefill’: False}
INFO 09-13 13:31:28 [config.py:1604] Using max model len 16384
INFO 09-13 13:31:28 [config.py:2434] Chunked prefill is enabled with max_num_batched_tokens=200000.
/usr/local/lib/python3.12/dist-packages/vllm/transformers_utils/tokenizer_group.py:24: FutureWarning: It is strongly recommended to run mistral models with --tokenizer-mode "mistral" to ensure correct encoding and decoding.
self.tokenizer = get_tokenizer(self.tokenizer_id, **tokenizer_config)
INFO 09-13 13:31:40 [init.py:235] Automatically detected platform cuda.
INFO 09-13 13:31:43 [core.py:572] Waiting for init message from front-end.
INFO 09-13 13:31:43 [core.py:71] Initializing a V1 LLM engine (v0.10.1.dev1+gbcc0a3cbe) with config: model=‘mistralai/Mistral-7B-Instruct-v0.2’, speculative_config=None, tokenizer=‘mistralai/Mistral-7B-Instruct-v0.2’, skip_tokenizer_init=False, tokenizer_mode=auto, revision=None, override_neuron_config={}, tokenizer_revision=None, trust_remote_code=True, dtype=torch.bfloat16, max_seq_len=16384, download_dir=None, load_format=LoadFormat.AUTO, tensor_parallel_size=1, pipeline_parallel_size=1, disable_custom_all_reduce=False, quantization=None, enforce_eager=False, kv_cache_dtype=auto, device_config=cuda, decoding_config=DecodingConfig(backend=‘auto’, disable_fallback=False, disable_any_whitespace=False, disable_additional_properties=False, reasoning_backend=‘’), observability_config=ObservabilityConfig(show_hidden_metrics_for_version=None, otlp_traces_endpoint=None, collect_detailed_traces=None), seed=0, served_model_name=mistralai/Mistral-7B-Instruct-v0.2, num_scheduler_steps=1, multi_step_stream_outputs=True, enable_prefix_caching=False, chunked_prefill_enabled=True, use_async_output_proc=True, pooler_config=None, compilation_config={“level”:3,“debug_dump_path”:“”,“cache_dir”:“”,“backend”:“”,“custom_ops”:,“splitting_ops”:[“vllm.unified_attention”,“vllm.unified_attention_with_output”,“vllm.mamba_mixer2”],“use_inductor”:true,“compile_sizes”:,“inductor_compile_config”:{“enable_auto_functionalized_v2”:false},“inductor_passes”:{},“use_cudagraph”:true,“cudagraph_num_of_warmups”:1,“cudagraph_capture_sizes”:[400,392,384,376,368,360,352,344,336,328,320,312,304,296,288,280,272,264,256,248,240,232,224,216,208,200,192,184,176,168,160,152,144,136,128,120,112,104,96,88,80,72,64,56,48,40,32,24,16,8,4,2,1],“cudagraph_copy_inputs”:false,“full_cuda_graph”:false,“max_capture_size”:400,“local_cache_dir”:null}
INFO 09-13 13:31:47 [parallel_state.py:1102] rank 0 in world size 1 is assigned as DP rank 0, PP rank 0, TP rank 0, EP rank 0
INFO 09-13 13:31:47 [topk_topp_sampler.py:49] Using FlashInfer for top-p & top-k sampling.
INFO 09-13 13:31:47 [gpu_model_runner.py:1843] Starting to load model mistralai/Mistral-7B-Instruct-v0.2…
INFO 09-13 13:31:47 [gpu_model_runner.py:1875] Loading model from scratch…
INFO 09-13 13:31:47 [cuda.py:290] Using Flash Attention backend on V1 engine.
INFO 09-13 13:31:48 [weight_utils.py:296] Using model weights format [‘*.safetensors’]
INFO 09-13 13:32:05 [weight_utils.py:312] Time spent downloading weights for mistralai/Mistral-7B-Instruct-v0.2: 17.724022 seconds

File “/tmp/.cache/vllm/torch_compile_cache/a78ce1dd12/rank_0_0/inductor_cache/6j/c6jmh45fb7kxj5t6tes7phcujte62jazw3pfh7sjket4ugwpqml4.py”, line 494, in call
buf4 = empty_strided_cuda((s0, 14336), (14336, 1), torch.bfloat16)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 5.34 GiB. GPU 0 has a total capacity of 79.25 GiB of which 4.67 GiB is free. Including non-PyTorch memory, this process has 74.57 GiB memory in use. Of the allocated memory 67.55 GiB is allocated by PyTorch, with 72.94 MiB allocated in private pools (e.g., CUDA Graphs), and 6.19 GiB is reserved by PyTorch but unallocated. If reserved but unallocated memory is large try setting PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True to avoid fragmentation. See documentation for Memory Management (CUDA semantics — PyTorch 2.8 documentation)

vLLM does not automatically cap or adjust max-num-batched-tokens based on available GPU memory; if you set this value too high, the server may fail with CUDA OOM errors rather than limiting concurrency or batch size. The recommended approach is to manually tune max-num-batched-tokens, max_num_seqs, or gpu_memory_utilization to fit within your hardware constraints, as described in the official memory conservation and optimization guides. There is no built-in mechanism to dynamically cap these parameters based on memory profiling at runtime—OOM is expected if the configuration exceeds available resources. See Conserving Memory and Optimization and Tuning.

To avoid OOM, reduce max-num-batched-tokens or max_num_seqs, or increase tensor_parallel_size to distribute memory usage across more GPUs. vLLM’s memory profiling can estimate available KV cache, but it does not auto-adjust user-specified limits; manual tuning is required. For more, see Parallelism and Scaling and Context length and batch size.

Would you like a step-by-step example of how to tune these parameters for your hardware?

Sources: