[Bugfix][Structured Outputs] Reject degenerate `structured_outputs` that crash EngineCore (#45346)

Signed-off-by: Ting Sun <suntcrick@gmail.com>

Ting SUN committed Jul 1, 2026 at 05:41 UTC ac521f623706b74ac12a01e6ed8f7297a39257fe
2 files changed +33
tests/v1/structured_output/test_validation.py
+21
@@ -48,3 +48,24 @@ def test_plain_request_allowed_for_diffusion_models():
48 StructuredOutputsConfig(),
49 tokenizer=None,
50 )
51 +
52 +
53 +@pytest.mark.parametrize(
54 + "structured_outputs, match",
55 + [
56 + (StructuredOutputsParams(json_object=False), "json_object must be True"),
57 + (StructuredOutputsParams(json=""), "json cannot be an empty string"),
58 + ],
59 +)
60 +def test_degenerate_structured_outputs_rejected(structured_outputs, match):
61 + """json_object=False and an empty json schema pass the `is not None`
62 + exclusivity check but resolve to no structured-output key, so they must be
63 + rejected at request validation (-> 400) instead of reaching and crashing
64 + the engine."""
65 + params = SamplingParams(structured_outputs=structured_outputs)
66 + with pytest.raises(ValueError, match=match):
67 + params._validate_structured_outputs(
68 + _StubModelConfig(is_diffusion=False),
69 + StructuredOutputsConfig(),
70 + tokenizer=object(),
71 + )
vllm/sampling_params.py
+12
@@ -938,6 +938,18 @@ class SamplingParams(
938 and self.structured_outputs.grammar.strip() == ""
939 ):
940 raise ValueError("structured_outputs.grammar cannot be an empty string")
941 + # Reject empty string json schema early to avoid engine-side crashes
942 + if (
943 + isinstance(self.structured_outputs.json, str)
944 + and self.structured_outputs.json.strip() == ""
945 + ):
946 + raise ValueError("structured_outputs.json cannot be an empty string")
947 + # Reject json_object=False early to avoid engine-side crashes
948 + if self.structured_outputs.json_object is False:
949 + raise ValueError(
950 + "structured_outputs.json_object must be True if set; omit "
951 + "structured_outputs to disable structured outputs"
952 + )
953
954 from vllm.v1.structured_output.backend_guidance import (
955 has_guidance_unsupported_json_features,