[Frontend] Migrate input-validation errors to VLLMValidationError (harmony/mistral/chat_utils/params) (#55735)

Signed-off-by: shaolila <shaolila@buaa.edu.cn> Co-authored-by: shaolila <shaolila@buaa.edu.cn>

Adababy committed Sep 8, 2026 at 14:45 UTC 5133e1d28594d5939552003f32b55a3fb18556a1
7 files changed +62 -8
tests/entrypoints/openai/test_render_parity.py
+14
@@ -29,6 +29,7 @@ from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionReque
29 from vllm.entrypoints.openai.responses.protocol import ResponsesRequest
30 from vllm.entrypoints.openai.responses.serving import OpenAIServingResponses
31 from vllm.entrypoints.serve.engine.protocol import ErrorResponse
32 +from vllm.exceptions import VLLMValidationError
33 from vllm.inputs import tokens_input
34 from vllm.renderers.online_renderer import OnlineRenderer
35 from vllm.renderers.params import ChatParams
@@ -427,6 +428,19 @@ class TestReasoningRenderParity:
428 },
429 )
430
431 + async def test_reasoning_effort_none_rejected_by_harmony(self, online_renderer):
432 + """Harmony rejects reasoning_effort="none" as invalid user input."""
433 + request = ChatCompletionRequest(
434 + model=_MODEL,
435 + messages=_USER,
436 + reasoning_effort="none",
437 + )
438 + with pytest.raises(
439 + VLLMValidationError, match="Harmony does not support"
440 + ) as exc_info:
441 + online_renderer._make_request_with_harmony(request)
442 + assert exc_info.value.parameter == "reasoning_effort"
443 +
444 async def test_explicit_enable_thinking_not_overridden(
445 self, online_renderer, serving_responses
446 ):
tests/entrypoints/unit_tests/test_chat_utils.py
+10
@@ -21,6 +21,7 @@ from vllm.entrypoints.chat_utils import (
21 _postprocess_messages,
22 parse_chat_messages,
23 parse_chat_messages_async,
24 + validate_chat_template,
25 )
26 from vllm.exceptions import VLLMValidationError
27 from vllm.inputs import MultiModalDataDict, MultiModalUUIDDict
@@ -3138,3 +3139,12 @@ def test_tool_call_arguments_multiple_independent(caplog):
3139
3140 assert len(caplog.records) == 1
3141 assert "bad" in caplog.records[0].message
3142 +
3143 +
3144 +def test_validate_chat_template_rejects_invalid_type():
3145 + """A non-str/Path chat_template is invalid user input."""
3146 + with pytest.raises(
3147 + VLLMValidationError, match="not a valid chat template type"
3148 + ) as exc_info:
3149 + validate_chat_template(123) # type: ignore[arg-type]
3150 + assert exc_info.value.parameter == "chat_template"
tests/tokenizers_/test_mistral.py
+14 -1
@@ -11,6 +11,7 @@ from mistral_common.guidance.grammar_factory import GrammarFactory
11 from mistral_common.tokens.tokenizers.base import SpecialTokenPolicy, SpecialTokens
12
13 from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionRequest
14 +from vllm.exceptions import VLLMValidationError
15 from vllm.tokenizers.mistral import (
16 MistralTokenizer,
17 _validate_apply_chat_template_args,
@@ -2279,8 +2280,20 @@ def test_validate_request_params_rejects_unsupported_effort() -> None:
2280 messages=[],
2281 reasoning_effort="medium",
2282 )
2282 - with pytest.raises(ValueError, match="reasoning_effort"):
2283 + with pytest.raises(VLLMValidationError, match="reasoning_effort") as exc_info:
2284 validate_request_params(request)
2285 + assert exc_info.value.parameter == "reasoning_effort"
2286 +
2287 +
2288 +def test_validate_request_params_rejects_chat_template() -> None:
2289 + request = ChatCompletionRequest(
2290 + model="test-model",
2291 + messages=[],
2292 + chat_template="{{ messages }}",
2293 + )
2294 + with pytest.raises(VLLMValidationError, match="chat_template") as exc_info:
2295 + validate_request_params(request)
2296 + assert exc_info.value.parameter == "chat_template"
2297
2298
2299 # ---------------------------------------------------------------------------
vllm/entrypoints/chat_utils.py
+4 -1
@@ -1454,7 +1454,10 @@ def validate_chat_template(chat_template: Path | str | None):
1454 )
1455
1456 else:
1457 - raise TypeError(f"{type(chat_template)} is not a valid chat template type")
1457 + raise VLLMValidationError(
1458 + f"{type(chat_template)} is not a valid chat template type",
1459 + parameter="chat_template",
1460 + )
1461
1462
1463 def _load_chat_template(
vllm/renderers/online_renderer.py
+4 -1
@@ -512,7 +512,10 @@ class OnlineRenderer:
512 assert not self.supports_browsing
513 assert not self.supports_code_interpreter
514 if (reasoning_effort := request.reasoning_effort) == "none":
515 - raise ValueError(f"Harmony does not support {reasoning_effort=}")
515 + raise VLLMValidationError(
516 + f"Harmony does not support {reasoning_effort=}",
517 + parameter="reasoning_effort",
518 + )
519 tools = request.tools if should_include_tools else None
520 messages.extend(
521 build_harmony_preamble(
vllm/renderers/params.py
+8 -2
@@ -445,9 +445,15 @@ class TokenizeParams:
445 return tokens
446
447 if tokenizer is None:
448 - raise ValueError("Cannot pad tokens when `skip_tokenizer_init=True`")
448 + raise VLLMValidationError(
449 + "Cannot pad tokens when `skip_tokenizer_init=True`",
450 + parameter="pad_prompt_tokens",
451 + )
452 if not isinstance(tokens, list):
450 - raise ValueError("Cannot pad tokens for embedding inputs")
453 + raise VLLMValidationError(
454 + "Cannot pad tokens for embedding inputs",
455 + parameter="pad_prompt_tokens",
456 + )
457
458 return tokens + [tokenizer.pad_token_id] * (pad_length - len(tokens))
459
vllm/tokenizers/mistral.py
+8 -3
@@ -34,6 +34,7 @@ from transformers.tokenization_mistral_common import MistralCommonBackend
34
35 from vllm.entrypoints.chat_utils import ChatCompletionMessageParam
36 from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionRequest
37 +from vllm.exceptions import VLLMValidationError
38 from vllm.logger import init_logger
39 from vllm.tokenizers.protocol import TokenizerLike
40
@@ -144,15 +145,19 @@ def _validate_apply_chat_template_args(
145
146 def validate_request_params(request: "ChatCompletionRequest"):
147 if request.chat_template is not None or request.chat_template_kwargs is not None:
147 - raise ValueError("chat_template is not supported for Mistral tokenizers.")
148 + raise VLLMValidationError(
149 + "chat_template is not supported for Mistral tokenizers.",
150 + parameter="chat_template",
151 + )
152
153 if request.reasoning_effort and request.reasoning_effort not in list(
154 ReasoningEffort
155 ):
152 - raise ValueError(
156 + raise VLLMValidationError(
157 f"reasoning_effort={request.reasoning_effort} is not supported by "
158 "Mistral models. Supported values are: "
155 - f"{[e.value for e in ReasoningEffort]}."
159 + f"{[e.value for e in ReasoningEffort]}.",
160 + parameter="reasoning_effort",
161 )
162
163