[Misc] Use VLLMValidationError in Cohere request validation (#52467)

Signed-off-by: frank-suwen <suwenw2@outlook.com>
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Frank
2026-08-24 00:52:27 +00:00
committed by GitHub
co-authored by Codex
parent 185cada36b
commit cd329413e2
3 changed files with 36 additions and 9 deletions
+8 -3
View File
@@ -36,6 +36,10 @@ from vllm.entrypoints.serve.exception_handling.handlers.http import (
from vllm.entrypoints.serve.exception_handling.handlers.validation import (
validation_exception_handler,
)
from vllm.entrypoints.serve.exception_handling.handlers.vllm_error import (
vllm_error_handler,
)
from vllm.exceptions import VLLMError
@pytest.fixture(autouse=True)
@@ -83,7 +87,7 @@ def _build_app(handler: _Handler | None) -> FastAPI:
def _build_app_with_vllm_handlers(handler: _Handler | None) -> FastAPI:
"""Build a FastAPI app that mirrors the real vLLM setup by installing
``validation_exception_handler`` and ``http_exception_handler``. The
validation, HTTP, and vLLM exception handlers. The
:class:`CohereErrorEnvelopeMiddleware` registered by ``attach_router``
is expected to translate any resulting vLLM ``ErrorResponse`` body
into the ``CohereError`` wire shape.
@@ -96,6 +100,7 @@ def _build_app_with_vllm_handlers(handler: _Handler | None) -> FastAPI:
app.state.args = Namespace(log_error_stack=False)
app.exception_handler(RequestValidationError)(validation_exception_handler)
app.exception_handler(HTTPException)(http_exception_handler)
app.exception_handler(VLLMError)(vllm_error_handler)
return app
@@ -333,8 +338,8 @@ class TestCohereErrorEnvelope:
def test_validation_error_body_is_cohere_shaped(self):
# ``model=""`` and ``messages=[]`` trip our custom field
# validators, which raise pydantic ValueErrors and are routed
# through ``validation_exception_handler`` in the real vLLM
# validators, which raise VLLMValidationError and are routed
# through ``vllm_error_handler`` in the real vLLM
# server (producing the ``{"error": {...}}`` shape).
app = _build_app_with_vllm_handlers(handler=None)
with TestClient(app) as client:
+17 -3
View File
@@ -6,7 +6,8 @@ The module is mostly a thin wrapper around the official ``cohere`` SDK
types plus a few local additions:
* :class:`CohereError` envelope.
* :class:`CohereChatV2Request` (model required, ``max_tokens`` non-negative).
* :class:`CohereChatV2Request` (model and messages required,
``max_tokens`` non-negative).
* :class:`CohereChatV2Response` plus the usage / logprob helpers.
* The streaming event subclasses that bake a wire-format ``type``
discriminator into ``model_dump()`` so SSE consumers can demux on it.
@@ -33,6 +34,7 @@ from vllm.entrypoints.cohere.protocol import (
ToolCallStartEvent,
ToolPlanDeltaEvent,
)
from vllm.exceptions import VLLMValidationError
# ======================================================================
# CohereError
@@ -52,16 +54,28 @@ class TestCohereError:
class TestCohereChatV2Request:
def test_empty_model_rejected(self):
with pytest.raises(ValidationError, match="model is required"):
with pytest.raises(VLLMValidationError, match="model is required") as exc_info:
CohereChatV2Request(model="", messages=[{"role": "user", "content": "hi"}])
assert exc_info.value.parameter == "model"
assert exc_info.value.value is None
def test_negative_max_tokens_rejected(self):
with pytest.raises(ValidationError, match="non-negative"):
with pytest.raises(VLLMValidationError, match="non-negative") as exc_info:
CohereChatV2Request(
model="m",
messages=[{"role": "user", "content": "hi"}],
max_tokens=-1,
)
assert exc_info.value.parameter == "max_tokens"
assert exc_info.value.value == -1
def test_empty_messages_rejected(self):
with pytest.raises(
VLLMValidationError, match="messages must contain at least one message"
) as exc_info:
CohereChatV2Request(model="m", messages=[])
assert exc_info.value.parameter == "messages"
assert exc_info.value.value is None
def test_zero_max_tokens_allowed(self):
# Zero is allowed (the docs allow 0 -> return prompt only).
+11 -3
View File
@@ -46,6 +46,8 @@ from cohere.types import (
)
from pydantic import BaseModel, Field, field_validator
from vllm.exceptions import VLLMValidationError
# Re-export the SDK wire-format types alongside our local extensions so
# ``vllm.entrypoints.cohere.serving`` and friends can import everything
# they need from this module.
@@ -186,14 +188,18 @@ class CohereChatV2Request(BaseModel):
@classmethod
def _validate_model(cls, v: str) -> str:
if not v:
raise ValueError("model is required")
raise VLLMValidationError("model is required", parameter="model")
return v
@field_validator("max_tokens")
@classmethod
def _validate_max_tokens(cls, v: int | None) -> int | None:
if v is not None and v < 0:
raise ValueError("max_tokens must be non-negative")
raise VLLMValidationError(
"max_tokens must be non-negative",
parameter="max_tokens",
value=v,
)
return v
@field_validator("messages", mode="before")
@@ -233,7 +239,9 @@ class CohereChatV2Request(BaseModel):
@classmethod
def _validate_messages(cls, v: list[ChatMessageV2]) -> list[ChatMessageV2]:
if not v:
raise ValueError("messages must contain at least one message")
raise VLLMValidationError(
"messages must contain at least one message", parameter="messages"
)
return v