{"record":{"id":"8d774058bdfba7da","repo":"vllm-project/vllm","slug":"invalid-structured-outputs-params-message","errorCode":null,"errorMessage":"invalid structured outputs params: {message}","messagePattern":"invalid structured outputs params: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"rust/src/engine-core-client/src/error.rs","lineNumber":31,"sourceCode":"\n/// Public error type for the Rust engine-core client.\n#[derive(Debug, Error, Macro)]\npub enum Error {\n    #[error(\"messagepack encode failed for {target_type}: {message}\")]\n    Encode {\n        target_type: &'static str,\n        message: String,\n    },\n    #[error(\"messagepack decode failed for {target_type}: {message}\")]\n    Decode {\n        target_type: &'static str,\n        message: String,\n    },\n    #[error(\"messagepack value decode failed\")]\n    ValueDecode(#[from] rmpv::decode::Error),\n    #[error(\"messagepack ext value decode failed: {message}\")]\n    ExtValueDecode { message: String },\n    #[error(\"invalid structured outputs params: {message}\")]\n    InvalidStructuredOutputsParams { message: String },\n    #[error(\"io error\")]\n    Io(#[from] std::io::Error),\n    #[error(\"transport error\")]\n    Transport(#[from] zeromq::ZmqError),\n    #[error(\"ZMQ runtime task failed\")]\n    ZmqRuntimeTask(#[from] tokio::task::JoinError),\n    #[error(\"engine core reported fatal failure\")]\n    EngineCoreDead,\n    #[error(\"startup handshake timed out while waiting for {stage} after {timeout:?}\")]\n    HandshakeTimeout {\n        stage: &'static str,\n        timeout: Duration,\n    },\n    #[error(\"engine input registration timed out after {timeout:?}\")]\n    InputRegistrationTimeout { timeout: Duration },\n    #[error(\"unexpected engine id in startup handshake: expected {expected:?}, got {actual:?}\")]\n    UnexpectedHandshakeIdentity { expected: Vec<u8>, actual: Vec<u8> },","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/vllm-project/vllm/blob/c794754062d49a8fdb63ab3c5215b488b865030c/rust/src/engine-core-client/src/error.rs#L13-L49","documentation":"Error::InvalidStructuredOutputsParams is returned by TryFrom<WireStructuredOutputsParams> for StructuredOutputsParams (rust/src/engine-core-client/src/protocol/structured_outputs.rs:150-183). It enforces that exactly one structured-output constraint is present: the insert_constraint! macro rejects a second constraint, json_object must be true if set, and a params object with no constraint at all is rejected ('missing structured output constraint').","triggerScenarios":"Building a request whose structured_outputs params contain: (a) two or more of json/regex/choice/grammar/json_object/structural_tag (message 'multiple structured output constraints specified: X, Y'), (b) json_object: false (must be omitted to disable), or (c) an options-only object with no constraint field ('missing structured output constraint').","commonSituations":"Translating OpenAI-style guided_decoding config where e.g. guided_json and guided_regex were both populated. Passing structured_outputs: {} as a 'disabled' marker instead of omitting the field. Frontends copying the whole sampling params object into every request.","solutions":["Set exactly one constraint field (json, regex, choice, grammar, structural_tag, or json_object: true)","To disable structured outputs, omit structured_outputs entirely — do not send json_object: false or an empty object","Strip null constraint fields at the frontend before building the request","Validate params before submit: StructuredOutputsParams::try_from(wire)? in a pre-flight check"],"exampleFix":"// before\nstructured_outputs: Some(WireStructuredOutputsParams {\n    json: Some(schema),\n    regex: Some(\"[0-9]+\".into()),\n    ..Default::default()\n}),\n\n// after\nstructured_outputs: Some(WireStructuredOutputsParams {\n    json: Some(schema),\n    ..Default::default()\n}),","handlingStrategy":"validation","validationCode":"fn exactly_one_constraint(p: &WireStructuredOutputsParams) -> bool {\n    let n = p.json.is_some() as u8 + p.regex.is_some() as u8 + p.choice.is_some() as u8\n        + p.grammar.is_some() as u8 + p.structural_tag.is_some() as u8\n        + p.json_object.map_or(0, |b| b as u8);\n    n == 1 && p.json_object != Some(false)\n}","typeGuard":"fn is_invalid_structured_outputs(e: &engine_core_client::Error) -> bool {\n    matches!(e, engine_core_client::Error::InvalidStructuredOutputsParams { .. })\n}","tryCatchPattern":"match StructuredOutputsParams::try_from(wire) {\n    Err(e @ engine_core_client::Error::InvalidStructuredOutputsParams { message }) => {\n        return bad_request(400, message); // surface to the API caller, do not retry\n    }\n    other => other?,\n}","preventionTips":["Normalize guided_* params at the HTTP layer: pick one constraint by precedence, null the rest","Omit structured_outputs entirely when unused; never send json_object: false as an off switch","Run TryFrom conversion at request admission, not deep in the send path"],"tags":["rust","structured-outputs","validation","request-building"],"backgroundTag":null,"analyzedSha":"c794754062d49a8fdb63ab3c5215b488b865030c","analyzedAt":"2026-08-14T21:17:39.825Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}