An oversized min_tokens in one request hangs the vLLM engine while /health stays green
What fixes it
No source in this snapshot names a fixed version.
Description
Summary
Any client that can reach /inference/v1/generate, mounted by default in v0.29.0 and unauthenticated unless --api-key is set, can stop vllm serve from serving with one request. The body sets sampling_params.max_tokens to null and min_tokens to 2147483648. The EngineCore, the single scheduler process, re-validates it in its input thread, which dies; the process stays up, /health answers 200, every later request hangs.
Root cause
The min_tokens <= max_tokens check runs in [_verify_args](https://github.com/vllm-project/vllm/blob/c1b69aa0d49b88016b5b2156ae61649c2c2df282/vllm/sampling_params.py#L616-L620) only when max_tokens is set. On /inference/v1/generate the API process builds SamplingParams directly from the JSON with max_tokens=None, so the check is skipped; the processor then [fills in max_tokens](https://github.com/vllm-project/vllm/blob/c1b69aa0d49b88016b5b2156ae61649c2c2df282/vllm/v1/engine/input_processor.py#L358-L362) (2045 here) without validating again and forwards the request.
In the EngineCore, [process_input_sockets](https://github.com/vllm-project/vllm/blob/c1b69aa0d49b88016b5b2156ae61649c2c2df282/vllm/v1/engine/core.py#L1757) decodes the message, which rebuilds SamplingParams and runs _verify_args a second time. Now both values are present and VLLMValidationError is raised on the decode line, one line above the try that protects request handling:
1757 req: EngineCoreRequest = add_request_decoder.decode(data_frames) # <- 1758 try: 1759 request = self.preprocess_add_request(req) ... 1765 except Exception: 1766 self._handle_request_preproc_error(req) 1767 continue
The exception is not caught, so the thread exits. It was the only reader of the input socket: no request reaches the scheduler any more, but nothing reports it, because the scheduler loop just waits on an empty queue, the thread is checked only at start-up, and [check_health](https://github.com/vllm-project/vllm/blob/c1b69aa0d49b88016b5b2156ae61649c2c2df282/vllm/v1/engine/async_llm.py#L1025-L1028) only looks for a recorded error. /health keeps answering 200 while every generation request hangs.
The OpenAI routes resolve max_tokens before building SamplingParams, so there the check runs in the API process and returns HTTP 400.
Impact
- Who can trigger it — Any network client, no credentials, that can reach
/inference/v1/generate: mounted by default on avllm serveof v0.29.0, and on main whenVLLM_ENABLE_SCALE_OUT_ENDPOINTS=1or--tokens-onlyis set. - What they get — One 92-byte request stops the server from serving any route for every client; later requests hang until the client gives up. The process stays alive and
/healthkeeps answering 200, so nothing restarts it. Recovery is a manual restart.
--- The initial discovery was made by AI scanning tools in Microsoft Security FORGE Labs, and later all technical claims has been reviewed and validated by human experts.
A public fix is available here: https://github.com/vllm-project/vllm/pull/57731
Text from GitHub Advisory Database
Affected versions 1
- vllm, pip< 0.31.0GitHub