Repository navigation
[Core][Rust Frontend] Report structured-output compile failures as validation errors - #62872
Merged
BugenZhao merged 2 commits intoOct 22, 2026
Conversation
…lidation errors A constraint EngineCore fails to compile finished the request as `FINISHED_ERROR` with no error attached, so frontends that do not validate constraints with the backend library (the Rust frontend) returned HTTP 500, and the guidance backend returned an empty 200 when llguidance built a matcher in an error state. - The scheduler attaches `RequestError(code="validation_error")` with the compile error, the code vllm-project#49625 introduced for a request whose backend differs from the engine's; Python already raises `VLLMValidationError` (400) for it. - The guidance backend fails compilation when the matcher reports an error instead of only logging it. - The Rust frontend maps `validation_error` to HTTP 400 / gRPC `INVALID_ARGUMENT`, and raw `/inference/v1/generate` fails on every typed engine error, as Python does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Bugen Zhao <i@bugenzhao.com>
BugenZhao
marked this pull request as ready for review
October 21, 2026 11:35
BugenZhao
requested review from
ApostaC,
WoosukKwon,
ZJY0516,
aarnphm,
alexm-redhat,
arpera,
heheda12345,
ivanium,
mgoin,
njhill,
orozery,
robertgshaw2-redhat and
ywang96
as code owners
October 21, 2026 11:35
njhill
approved these changes
Oct 21, 2026
Member
Author
|
/ci run |
|
✅ Triggered Buildkite CI #96538 for commit ℹ️ This PR is 43 commits behind upstream |
10 tasks
6 tasks done
bantianyue
pushed a commit
to bantianyue/vllm
that referenced
this pull request
Oct 28, 2026
…lidation errors (vllm-project#62872) Signed-off-by: Bugen Zhao <i@bugenzhao.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: vllm-agent <claw@inferact.ai>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
A structured-output constraint that EngineCore fails to compile finishes the request as
FINISHED_ERRORwith no error attached. The Python frontend rarely sees this, because it validates constraints with the backend library before submitting. The Rust frontend cannot, so its clients get HTTP 500 for an invalid regex or grammar, and an empty 200 when llguidance builds a matcher in an error state (for example a schema withuniqueItems). This PR reports compile failures with thevalidation_errorcode that #49625 introduced for backend mismatches, so both frontends return 400, and makes the guidance backend fail compilation instead of continuing with a broken matcher.Claims
RequestError(code="validation_error", message="Invalid structured outputs: <compile error>"). Python already maps that code toVLLMValidationError(400) since [Bugfix] Reject mixed structured output backends during validation #49625.Grammar error: ...) instead of logging a warning and generating nothing.validation_errorto HTTP 400 (an SSEBadRequestErrorevent when streaming) and gRPCINVALID_ARGUMENT. This also covers [Bugfix] Reject mixed structured output backends during validation #49625's backend-mismatch rejection, which the Rust frontend reported as 500./inference/v1/generatefails the request on every engine-typed error, as Python raises everyRequestError; before, only retryable ones did.Validation
GPU smoke on GB200, Qwen3-8B with
--reasoning-parser qwen3 --tool-call-parser hermesviaVLLM_USE_RUST_FRONTEND=1 vllm serve,main(e9cc6244a0) against this PR. Onmainthe Rust frontend sends native HTTP constraints as guidance and parser-built output grammars as xgrammar, and EngineCore keeps the first request's backend, so two request orders cover both backends and #49625's mismatch rejection. Each order ends with a valid request; the engine stays healthy on both builds.mainregex: "("Grammar error: ... unclosed groupgrammar: "root ::= ("Failed to convert the grammar from GBNF to Lark ...{"type": "array", "uniqueItems": true}Grammar error: Unimplemented keys: ["uniqueItems"]regex(composed into an xgrammar tag, mismatch)... only supports one backend per engine ...regex: "("(composed)Regex parsing error at position 2 ...grammar: "root ::= ("InternalServerErrorBadRequestErrorregex(guidance, mismatch)... only supports one backend per engine ...Tests:
tests/v1/core/test_scheduler.py,test_async_scheduler.py,tests/v1/structured_output/test_backend_guidance.py,test_validation.py,tests/test_outputs.py): 104 passed.test_grammar_compile_error_finishes_only_requestnow asserts the error output'sRequestError; the newtest_backend_guidance_rejects_grammar_matcher_cannot_buildcompiles auniqueItemsschema. Both fail with the engine changes reverted (errorisNone; compilation does not raise).cargo nextest run --workspace(2229 passed), clippy, fmt.engine_request_errors_map_to_http_status(wasretryable_engine_error_returns_service_unavailable) runs a retryable and a validation error through completions, chat, and raw generate against the mock engine;engine_errors_map_to_status_codescovers gRPC.Details
Root cause. Grammar compilation runs asynchronously after
StructuredOutputManager.grammar_init. Since #47312, a failed compilation finishes only that request, throughgrammar_compile_error_reqs, but without aRequestError, so every frontend reports an internal error. #49625 addedvalidation_errorfor the separate case where a request names a backend other than the one the engine already uses; that check runs ingrammar_init, before compilation, and does not cover a constraint that the right backend fails to compile. The guidance backend creates itsLLMatcherwithout failing on a build error:check_error()only logs it, and the matcher allows nothing, so the request ends with empty output.Why
validation_error. It is the existing "the request itself is invalid" signal onRequestError, and Python'sto_exceptionalready maps it to 400; a compile failure of the request's own constraint is the same kind of error. Python's frontend validation already returns 400 for these constraints when it can check them, so this only changes requests that reach the engine unvalidated. The Rust side addsRequestError::VALIDATION_ERRORandis_validation_error()next to the existingretryablehandling rather than an enum:codeis an open string on the Python side, and no other code needs distinct Rust behavior.Not changed.
[time] /project/cpp/...:line:). Python's HTTP layer rewrites such paths withsanitize_message; the Rust frontend passes the message through.Not a duplicate.
Pull Request Checklist
I used vLLM's
/pr-checklistskill. (Mandatory for agents, optional for humans).AI assistance was used during the creation of this PR.
Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.
Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.
Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.
Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.
AI assistance (Claude) was used to investigate, write, and test this change. I reviewed every changed line and ran the tests and GPU smoke above.
🤖 Generated with Claude Code