@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 1ab055efe6
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 10, 14:00 UTC

[OpenAI] Extend VLLMValidationError to additional validation parameters (#31870)

Signed-off-by: Rehan Khan <Rehan.Khan7@ibm.com>

R3hankhan committed Jan 7, 2026 at 20:15 UTC 1ab055efe6b7f9abdd8774ed64ead1b83dd00253
9 files changed +89 -56
vllm/entrypoints/openai/api_server.py
+1 -1
@@ -911,7 +911,7 @@ def build_app(args: Namespace) -> FastAPI:
911
912 @app.exception_handler(RequestValidationError)
913 async def validation_exception_handler(_: Request, exc: RequestValidationError):
914 - from vllm.entrypoints.openai.protocol import VLLMValidationError
914 + from vllm.exceptions import VLLMValidationError
915
916 param = None
917 for error in exc.errors():
vllm/entrypoints/openai/protocol.py
+1 -30
@@ -72,6 +72,7 @@ from pydantic import (
72 )
73
74 from vllm.entrypoints.chat_utils import ChatCompletionMessageParam, make_tool_call_id
75 +from vllm.exceptions import VLLMValidationError
76 from vllm.logger import init_logger
77 from vllm.logprobs import Logprob
78 from vllm.sampling_params import (
@@ -131,36 +132,6 @@ class ErrorResponse(OpenAIBaseModel):
132 error: ErrorInfo
133
134
134 -class VLLMValidationError(ValueError):
135 - """vLLM-specific validation error for request validation failures.
136 -
137 - Args:
138 - message: The error message describing the validation failure.
139 - parameter: Optional parameter name that failed validation.
140 - value: Optional value that was rejected during validation.
141 - """
142 -
143 - def __init__(
144 - self,
145 - message: str,
146 - *,
147 - parameter: str | None = None,
148 - value: Any = None,
149 - ) -> None:
150 - super().__init__(message)
151 - self.parameter = parameter
152 - self.value = value
153 -
154 - def __str__(self):
155 - base = super().__str__()
156 - extras = []
157 - if self.parameter is not None:
158 - extras.append(f"parameter={self.parameter}")
159 - if self.value is not None:
160 - extras.append(f"value={self.value}")
161 - return f"{base} ({', '.join(extras)})" if extras else base
162 -
163 -
135 class ModelPermission(OpenAIBaseModel):
136 id: str = Field(default_factory=lambda: f"modelperm-{random_uuid()}")
137 object: str = "model_permission"
vllm/entrypoints/openai/serving_completion.py
+4 -4
@@ -140,16 +140,16 @@ class OpenAIServingCompletion(OpenAIServing):
140 )
141 except ValueError as e:
142 logger.exception("Error in preprocessing prompt inputs")
143 - return self.create_error_response(str(e))
143 + return self.create_error_response(e)
144 except TypeError as e:
145 logger.exception("Error in preprocessing prompt inputs")
146 - return self.create_error_response(str(e))
146 + return self.create_error_response(e)
147 except RuntimeError as e:
148 logger.exception("Error in preprocessing prompt inputs")
149 - return self.create_error_response(str(e))
149 + return self.create_error_response(e)
150 except jinja2.TemplateError as e:
151 logger.exception("Error in preprocessing prompt inputs")
152 - return self.create_error_response(str(e))
152 + return self.create_error_response(e)
153
154 # Extract data_parallel_rank from header (router can inject it)
155 data_parallel_rank = self._get_data_parallel_rank(raw_request)
vllm/entrypoints/openai/serving_engine.py
+1 -1
@@ -754,7 +754,7 @@ class OpenAIServing:
754 if isinstance(message, Exception):
755 exc = message
756
757 - from vllm.entrypoints.openai.protocol import VLLMValidationError
757 + from vllm.exceptions import VLLMValidationError
758
759 if isinstance(exc, VLLMValidationError):
760 err_type = "BadRequestError"
vllm/entrypoints/openai/serving_responses.py
+1 -1
@@ -373,7 +373,7 @@ class OpenAIServingResponses(OpenAIServing):
373 NotImplementedError,
374 ) as e:
375 logger.exception("Error in preprocessing prompt inputs")
376 - return self.create_error_response(f"{e} {e.__cause__}")
376 + return self.create_error_response(e)
377
378 request_metadata = RequestResponseMetadata(request_id=request.request_id)
379 if raw_request:
vllm/entrypoints/renderer.py
+1 -1
@@ -12,7 +12,7 @@ import torch
12 from pydantic import Field
13
14 from vllm.config import ModelConfig
15 -from vllm.entrypoints.openai.protocol import VLLMValidationError
15 +from vllm.exceptions import VLLMValidationError
16 from vllm.inputs.data import EmbedsPrompt, TextPrompt, TokensPrompt
17 from vllm.inputs.parse import get_prompt_components, parse_raw_prompts
18 from vllm.tokenizers import TokenizerLike
vllm/exceptions.py new
+36
@@ -0,0 +1,36 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +
4 +"""Custom exceptions for vLLM."""
5 +
6 +from typing import Any
7 +
8 +
9 +class VLLMValidationError(ValueError):
10 + """vLLM-specific validation error for request validation failures.
11 +
12 + Args:
13 + message: The error message describing the validation failure.
14 + parameter: Optional parameter name that failed validation.
15 + value: Optional value that was rejected during validation.
16 + """
17 +
18 + def __init__(
19 + self,
20 + message: str,
21 + *,
22 + parameter: str | None = None,
23 + value: Any = None,
24 + ) -> None:
25 + super().__init__(message)
26 + self.parameter = parameter
27 + self.value = value
28 +
29 + def __str__(self):
30 + base = super().__str__()
31 + extras = []
32 + if self.parameter is not None:
33 + extras.append(f"parameter={self.parameter}")
34 + if self.value is not None:
35 + extras.append(f"value={self.value}")
36 + return f"{base} ({', '.join(extras)})" if extras else base
vllm/sampling_params.py
+31 -12
@@ -11,6 +11,7 @@ from typing import Annotated, Any
11 import msgspec
12 from pydantic.dataclasses import dataclass
13
14 +from vllm.exceptions import VLLMValidationError
15 from vllm.logger import init_logger
16 from vllm.logits_process import LogitsProcessor
17 from vllm.tokenizers import TokenizerLike
@@ -393,11 +394,17 @@ class SamplingParams(
394 f"{self.repetition_penalty}."
395 )
396 if self.temperature < 0.0:
396 - raise ValueError(
397 - f"temperature must be non-negative, got {self.temperature}."
397 + raise VLLMValidationError(
398 + f"temperature must be non-negative, got {self.temperature}.",
399 + parameter="temperature",
400 + value=self.temperature,
401 )
402 if not 0.0 < self.top_p <= 1.0:
400 - raise ValueError(f"top_p must be in (0, 1], got {self.top_p}.")
403 + raise VLLMValidationError(
404 + f"top_p must be in (0, 1], got {self.top_p}.",
405 + parameter="top_p",
406 + value=self.top_p,
407 + )
408 # quietly accept -1 as disabled, but prefer 0
409 if self.top_k < -1:
410 raise ValueError(
@@ -410,7 +417,11 @@ class SamplingParams(
417 if not 0.0 <= self.min_p <= 1.0:
418 raise ValueError(f"min_p must be in [0, 1], got {self.min_p}.")
419 if self.max_tokens is not None and self.max_tokens < 1:
413 - raise ValueError(f"max_tokens must be at least 1, got {self.max_tokens}.")
420 + raise VLLMValidationError(
421 + f"max_tokens must be at least 1, got {self.max_tokens}.",
422 + parameter="max_tokens",
423 + value=self.max_tokens,
424 + )
425 if self.min_tokens < 0:
426 raise ValueError(
427 f"min_tokens must be greater than or equal to 0, got {self.min_tokens}."
@@ -421,24 +432,30 @@ class SamplingParams(
432 f"max_tokens={self.max_tokens}, got {self.min_tokens}."
433 )
434 if self.logprobs is not None and self.logprobs != -1 and self.logprobs < 0:
424 - raise ValueError(
425 - f"logprobs must be non-negative or -1, got {self.logprobs}."
435 + raise VLLMValidationError(
436 + f"logprobs must be non-negative or -1, got {self.logprobs}.",
437 + parameter="logprobs",
438 + value=self.logprobs,
439 )
440 if (
441 self.prompt_logprobs is not None
442 and self.prompt_logprobs != -1
443 and self.prompt_logprobs < 0
444 ):
432 - raise ValueError(
445 + raise VLLMValidationError(
446 f"prompt_logprobs must be non-negative or -1, got "
434 - f"{self.prompt_logprobs}."
447 + f"{self.prompt_logprobs}.",
448 + parameter="prompt_logprobs",
449 + value=self.prompt_logprobs,
450 )
451 if self.truncate_prompt_tokens is not None and (
452 self.truncate_prompt_tokens == 0 or self.truncate_prompt_tokens < -1
453 ):
439 - raise ValueError(
454 + raise VLLMValidationError(
455 f"truncate_prompt_tokens must be an integer >= 1 or -1, "
441 - f"got {self.truncate_prompt_tokens}"
456 + f"got {self.truncate_prompt_tokens}",
457 + parameter="truncate_prompt_tokens",
458 + value=self.truncate_prompt_tokens,
459 )
460 assert isinstance(self.stop_token_ids, list)
461 if not all(isinstance(st_id, int) for st_id in self.stop_token_ids):
@@ -516,12 +533,14 @@ class SamplingParams(
533 if token_id < 0 or token_id > tokenizer.max_token_id
534 ]
535 if len(invalid_token_ids) > 0:
519 - raise ValueError(
536 + raise VLLMValidationError(
537 f"The model vocabulary size is {tokenizer.max_token_id + 1},"
538 f" but the following tokens"
539 f" were specified as bad: {invalid_token_ids}."
540 f" All token id values should be integers satisfying:"
524 - f" 0 <= token_id <= {tokenizer.max_token_id}."
541 + f" 0 <= token_id <= {tokenizer.max_token_id}.",
542 + parameter="bad_words",
543 + value=self.bad_words,
544 )
545
546 @cached_property
vllm/v1/engine/input_processor.py
+13 -6
@@ -6,6 +6,7 @@ from collections.abc import Mapping
6 from typing import Any, Literal, cast
7
8 from vllm.config import VllmConfig
9 +from vllm.exceptions import VLLMValidationError
10 from vllm.inputs import ProcessorInputs, PromptType, SingletonInputs
11 from vllm.inputs.parse import split_enc_dec_inputs
12 from vllm.inputs.preprocess import InputPreprocessor
@@ -83,9 +84,11 @@ class InputProcessor:
84 if num_logprobs == -1:
85 num_logprobs = self.model_config.get_vocab_size()
86 if num_logprobs > max_logprobs:
86 - raise ValueError(
87 + raise VLLMValidationError(
88 f"Requested sample logprobs of {num_logprobs}, "
88 - f"which is greater than max allowed: {max_logprobs}"
89 + f"which is greater than max allowed: {max_logprobs}",
90 + parameter="logprobs",
91 + value=num_logprobs,
92 )
93
94 # Validate prompt logprobs.
@@ -94,9 +97,11 @@ class InputProcessor:
97 if num_prompt_logprobs == -1:
98 num_prompt_logprobs = self.model_config.get_vocab_size()
99 if num_prompt_logprobs > max_logprobs:
97 - raise ValueError(
100 + raise VLLMValidationError(
101 f"Requested prompt logprobs of {num_prompt_logprobs}, "
99 - f"which is greater than max allowed: {max_logprobs}"
102 + f"which is greater than max allowed: {max_logprobs}",
103 + parameter="prompt_logprobs",
104 + value=num_prompt_logprobs,
105 )
106
107 def _validate_sampling_params(
@@ -134,9 +139,11 @@ class InputProcessor:
139 invalid_token_ids.append(token_id)
140
141 if invalid_token_ids:
137 - raise ValueError(
142 + raise VLLMValidationError(
143 f"token_id(s) {invalid_token_ids} in logit_bias contain "
139 - f"out-of-vocab token ids. Vocabulary size: {vocab_size}"
144 + f"out-of-vocab token ids. Vocabulary size: {vocab_size}",
145 + parameter="logit_bias",
146 + value=invalid_token_ids,
147 )
148
149 def _validate_supported_sampling_params(