{"record":{"id":"0f71d23aea31af3c","repo":"zylon-ai/private-gpt","slug":"invalid-request-error-0f71d2","errorCode":"INVALID_REQUEST_ERROR","errorMessage":"structured_outputs must be a StructuredOutputsParams, mapping, JSON object string, or None","messagePattern":"structured_outputs must be a StructuredOutputsParams, mapping, JSON object string, or None","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"private_gpt/components/llm/custom/base.py","lineNumber":122,"sourceCode":"    structured_outputs: (StructuredOutputsParams | Mapping[str, Any] | str | None),\n) -> StructuredOutputsParams | None:\n    \"\"\"Normalize structured-output values crossing untyped boundaries.\n\n    Chat parameters can be restored from serialized checkpoint data, and some\n    API serializers use ``json`` instead of the model's internal\n    ``json_schema`` field. Normalize those representations before backend\n    specific code accesses the typed fields.\n    \"\"\"\n    if structured_outputs is None:\n        return None\n    if isinstance(structured_outputs, StructuredOutputsParams):\n        return structured_outputs\n\n    if isinstance(structured_outputs, str):\n        try:\n            structured_outputs = json.loads(structured_outputs)\n        except json.JSONDecodeError as exc:\n            raise ValueError(\n                \"structured_outputs must be a StructuredOutputsParams, \"\n                \"mapping, JSON object string, or None\"\n            ) from exc\n        if not isinstance(structured_outputs, Mapping):\n            raise TypeError(\n                \"structured_outputs JSON must decode to an object; \"\n                f\"got {type(structured_outputs).__name__}\"\n            )\n\n    if isinstance(structured_outputs, Mapping):\n        values = dict(structured_outputs)\n        if \"json\" in values and \"json_schema\" not in values:\n            values[\"json_schema\"] = values.pop(\"json\")\n        return StructuredOutputsParams.model_validate(values)\n\n    raise TypeError(\n        \"structured_outputs must be a StructuredOutputsParams, mapping, \"\n        \"JSON object string, or None; \"","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/llm/custom/base.py#L104-L140","documentation":"ValueError raised while normalizing a structured_outputs parameter: the value was a string, but json.loads failed to parse it as JSON. The normalizer accepts StructuredOutputsParams, mappings, JSON-object strings, or None — a malformed JSON string fails at the json.loads step with this message, chained from JSONDecodeError.","triggerScenarios":"Passing structured_outputs as a string like \"{json_schema: ...}\" (missing quotes / trailing commas / truncated payload) to an LLM call that normalizes the parameter via this function. Any syntactically invalid JSON string triggers it.","commonSituations":"Schema strings built by manual f-string concatenation instead of json.dumps; user-supplied schema from a request body pasted with smart quotes or newlines; truncated payloads from proxies; double-encoded JSON.","solutions":["Build the JSON string with json.dumps(schema_dict) instead of hand-writing it.","Paste the string into a JSON validator (or json.loads in a REPL) to find the syntax error position from the chained JSONDecodeError.","Prefer passing the schema as a dict/StructuredOutputsParams object rather than a string.","Check for double-encoded JSON (a string containing an escaped JSON string) and decode once."],"exampleFix":"# before\nllm.chat(messages, structured_outputs='{\"json_schema\": ' + schema_str)  # broken拼接\n\n# after\nimport json\nllm.chat(messages, structured_outputs=json.dumps({\"json_schema\": schema_dict}))","handlingStrategy":"validation","validationCode":"import json\nif isinstance(structured_outputs, str):\n    try:\n        json.loads(structured_outputs)\n    except json.JSONDecodeError as e:\n        raise ValueError(f'invalid structured_outputs JSON at pos {e.pos}: {e.msg}') from e","typeGuard":"def is_valid_structured_outputs_str(value: str) -> bool:\n    try:\n        obj = json.loads(value)\n    except json.JSONDecodeError:\n        return False\n    return isinstance(obj, dict)","tryCatchPattern":"try:\n    llm.stream_chat(messages, structured_outputs=schema_str)\nexcept ValueError as e:\n    if 'structured_outputs must be' in str(e):\n        schema_str = json.dumps(schema_dict)  # rebuild safely and retry","preventionTips":["Never hand-concatenate schema strings; always json.dumps.","Validate request-supplied schema strings at the API boundary, not deep in the LLM layer."],"tags":["llm","structured-output","json","validation"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}