[Frontend] Migrate Responses API validation errors to VLLMValidationError (#50257)

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

Adababy committed Sep 7, 2026 at 17:33 UTC 7dbe38683325126de96d442d6b494f4266001bec
4 files changed +27 -10
tests/entrypoints/openai/parser/test_harmony_utils.py
+4 -2
@@ -20,6 +20,7 @@ from vllm.entrypoints.openai.responses.harmony import (
20 response_input_to_harmony,
21 response_previous_input_to_harmony,
22 )
23 +from vllm.exceptions import VLLMValidationError
24
25 _TOOL_PARAMETERS = {
26 "type": "object",
@@ -975,10 +976,11 @@ class TestGetSystemMessage:
976
977 def test_unsupported_reasoning_effort_raises_clear_error(self) -> None:
978 with pytest.raises(
978 - ValueError,
979 + VLLMValidationError,
980 match="reasoning_effort='max' is not supported by Harmony",
980 - ):
981 + ) as exc_info:
982 get_system_message(reasoning_effort="max")
983 + assert exc_info.value.parameter == "reasoning_effort"
984
985
986 class TestResponseInputToHarmonyReasoningItem:
tests/entrypoints/openai/responses/test_responses_utils.py
+6 -3
@@ -22,6 +22,7 @@ from vllm.entrypoints.openai.responses.utils import (
22 construct_input_messages,
23 should_continue_final_message,
24 )
25 +from vllm.exceptions import VLLMValidationError
26
27
28 def _single_chat_message(item):
@@ -223,8 +224,9 @@ class TestResponsesUtils:
224 encrypted_content="TOP_SECRET_MESSAGE",
225 status=None,
226 )
226 - with pytest.raises(ValueError):
227 + with pytest.raises(VLLMValidationError) as exc_info:
228 construct_chat_messages_with_tool_call([item])
229 + assert exc_info.value.parameter == "input"
230
231 output_item = ResponseOutputMessage(
232 id="msg_bf585bbbe3d500e0",
@@ -350,7 +352,7 @@ class TestReasoningItemContentPriority:
352 assert formatted["reasoning"] == ""
353
354 def test_encrypted_content_raises(self):
353 - """Encrypted content should still raise ValueError."""
355 + """Encrypted content should raise VLLMValidationError."""
356 item = ResponseReasoningItem(
357 id="reasoning_6",
358 summary=[
@@ -369,8 +371,9 @@ class TestReasoningItemContentPriority:
371 encrypted_content="ENCRYPTED",
372 status=None,
373 )
372 - with pytest.raises(ValueError):
374 + with pytest.raises(VLLMValidationError) as exc_info:
375 construct_chat_messages_with_tool_call([item])
376 + assert exc_info.value.parameter == "input"
377
378 @patch("vllm.entrypoints.openai.responses.utils.logger")
379 def test_summary_with_multiple_entries_uses_first(self, mock_logger):
vllm/entrypoints/openai/parser/harmony_utils.py
+12 -4
@@ -24,6 +24,7 @@ from openai_harmony import (
24
25 from vllm import envs
26 from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionToolsParam
27 +from vllm.exceptions import VLLMValidationError
28 from vllm.logger import init_logger
29
30 logger = init_logger(__name__)
@@ -123,9 +124,10 @@ def get_system_message(
124 if reasoning_effort is not None:
125 if reasoning_effort not in REASONING_EFFORT:
126 supported_values = ", ".join(REASONING_EFFORT)
126 - raise ValueError(
127 + raise VLLMValidationError(
128 f"reasoning_effort={reasoning_effort!r} is not supported by "
128 - f"Harmony. Supported values are: {supported_values}."
129 + f"Harmony. Supported values are: {supported_values}.",
130 + parameter="reasoning_effort",
131 )
132 sys_msg_content = sys_msg_content.with_reasoning_effort(
133 REASONING_EFFORT[reasoning_effort]
@@ -181,7 +183,10 @@ def get_developer_message(
183 elif tool.type == "function":
184 function_tools.append(tool)
185 else:
184 - raise ValueError(f"tool type {tool.type} not supported")
186 + raise VLLMValidationError(
187 + f"tool type {tool.type!r} is not supported.",
188 + parameter="tools",
189 + )
190 if function_tools:
191 function_tool_descriptions = [
192 create_tool_definition(tool) for tool in function_tools
@@ -297,7 +302,10 @@ def extract_instructions_from_messages(
302 elif hasattr(first_message, "model_dump"):
303 first_message = first_message.model_dump(exclude_none=True)
304 else:
300 - raise ValueError(f"Unknown message type: {type(first_message)}")
305 + raise VLLMValidationError(
306 + f"Unknown message type: {type(first_message)}",
307 + parameter="input",
308 + )
309
310 if first_message.get("role") not in (
311 "system",
vllm/entrypoints/openai/responses/utils.py
+5 -1
@@ -37,6 +37,7 @@ from vllm.entrypoints.openai.chat_completion.protocol import (
37 ChatCompletionToolsParam,
38 )
39 from vllm.entrypoints.openai.responses.protocol import ResponseInputOutputItem
40 +from vllm.exceptions import VLLMValidationError
41 from vllm.logger import init_logger
42 from vllm.tool_parsers.utils import (
43 build_responses_tool_call_name_map,
@@ -273,7 +274,10 @@ def _construct_message_from_response_item(
274 elif isinstance(item, ResponseReasoningItem):
275 reasoning = ""
276 if item.encrypted_content:
276 - raise ValueError("Encrypted content is not supported.")
277 + raise VLLMValidationError(
278 + "Encrypted content is not supported.",
279 + parameter="input",
280 + )
281 elif item.content and len(item.content) >= 1:
282 reasoning = item.content[0].text
283 elif len(item.summary) >= 1: