Repository navigation
Conversation
Reject a structured-output JSON schema nested more than 64 levels of objects and arrays, or a structural tag nested more than 64 + 16 levels, with a 400 before the request reaches EngineCore, matching Python's `check_json_nesting` (vllm-project#60036). Grammar conversion cost grows steeply with nesting, so an over-deep schema stalls compilation. The check walks the parsed value in `StructuredOutputsParams::validate`, which runs on the response_format conversion, the structured_outputs wire boundary, and the final constraint in `lower_sampling_params`, so parser-built tool-call structural tags are covered too. A structural tag is parsed first and rejected if it is not valid JSON, as Python's backend validation does, so a tag past serde_json's 128-level parse limit cannot skip the check. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Isotr0py
approved these changes
Oct 20, 2026
Member
Author
|
/ci run |
|
✅ Triggered Buildkite CI #96155 for commit ℹ️ This PR is 9 commits behind upstream |
bantianyue
pushed a commit
to bantianyue/vllm
that referenced
this pull request
Oct 28, 2026
…-project#62661) 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
Python rejects a structured-output JSON schema nested more than 64 levels deep, and a structural tag nested more than 64 + 16 levels, with a 400 (
check_json_nestinginvllm/sampling_params.py, #60036). The Rust frontend has no cap and forwards any schema to EngineCore, where grammar conversion cost grows roughly with size × depth²: #60036 measured 98 s for a depth-512 structural tag. This PR applies the same caps and message in the Rust frontend.Claims
response_format,structured_outputson chat, completions, and generate, and the tool-call structural tags that output parsers build.Validation
Commands from
.buildkite/scripts/run-rust-frontend-cargo-ci.sh(style-clippyandtest), run from the repo root:validate_caps_json_schema_nesting(vllm-engine-core-client): 64 levels pass and 65 fail with Python's message, both as a schema object and as a JSON string.validate_caps_structural_tag_nesting_with_wrapper_allowance: a structural tag passes at 80 levels and fails at 81.validate_rejects_malformed_structural_tag: a non-JSON structural tag returns "Invalid structural tag specification."prepare_chat_request_rejects_deeply_nested_json_schema(vllm-server): a chatresponse_formatwith a 65-level schema returns 400 with the message.The behavioral tests fail with the check removed from
validate.Details
The check lives in
StructuredOutputsParams::validate(vllm-engine-core-client), the existing owner of Python's_validate_structured_outputsrules. It already runs at every entry point, includinglower_sampling_paramson the final constraint, so parser-built tool-call structural tags are covered as in Python. A newnestingsubmodule sits next to the existingxgrammarone. Every constraint is checked on its parsed value: the schema check runs at the start ofvalidate_json_schema, which both JSON branches already call, and a structural tag is parsed and then checked.serde_jsonstops parsing at 128 levels, so a document deeper than that is rejected as invalid JSON (still a 400, with a different message than Python's). For the same reason a structural tag that fails to parse is rejected, so a tag past the parse limit cannot skip the check.One difference: Rust's parser-built structural tags nest tool argument schemas up to 20 wrapper levels deep (Python's stay within 15), so for that parser a strict tool's parameter schema is effectively capped near 62 levels instead of 64. Real tool schemas are far below either limit, so this PR keeps Python's single 16-level allowance.
Not a duplicate: no open upstream PR adds a nesting cap to the Rust frontend; #62506 validates JSON Schema keyword values in the Python frontend.
AI assistance (Claude Code) was used to prepare this change; the human submitter reviewed every changed line.
🤖 Generated with Claude Code
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.