{"record":{"id":"7e12b64842ab6da4","repo":"zylon-ai/private-gpt","slug":"tools-are-not-supported-when-response-format-is-se","errorCode":null,"errorMessage":"Tools are not supported when response_format is set to json_schema","messagePattern":"Tools are not supported when response_format is set to json_schema","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"error","filePath":"private_gpt/server/chat/chat_models.py","lineNumber":359,"sourceCode":"            )\n\n        # Apply global tool context to tools without specific context\n        if self.tools is not None:\n            global_tool_context = self.tool_context or []\n            if global_tool_context:\n                for tool in self.tools:\n                    if tool.context is None:\n                        tool.context = global_tool_context\n\n        has_structured_output = bool(self.output_config and self.output_config.format)\n        if self.response_format.type == ResponseFormatType.json_schema:\n            has_structured_output = True\n\n        # Check that we don't have tools when structured output is enabled\n        if has_structured_output:\n            if self.tools:\n                if self.response_format.type == ResponseFormatType.json_schema:\n                    raise ValueError(\n                        \"Tools are not supported when response_format is set to json_schema\"\n                    )\n                raise ValueError(\n                    \"Tools are not supported when structured output is enabled.\"\n                )\n            if self.mcp_servers:\n                raise ValueError(\n                    \"MCP servers are not supported when structured output is enabled.\"\n                )\n            if system.citations.enabled:\n                raise ValueError(\n                    \"Citations are not supported when structured output is enabled.\"\n                )\n\n        # Check unique tools\n        if self.tools:\n            tool_names = [tool.name for tool in self.tools]\n            if len(tool_names) != len(set(tool_names)):","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/server/chat/chat_models.py#L341-L377","documentation":"ChatBody's structured-output guard: when response_format.type is json_schema AND tools are present, the request is rejected. Structured output via json_schema and function/tool calling are treated as mutually exclusive — the response must be schema-conformant JSON, which tool calls would break.","triggerScenarios":"tool_choice={\"type\":\"tool\",\"name\":\"lookup\"} while tools only defines e.g. 'search'; renaming a tool in the tools registry without updating the client's tool_choice; dynamic tool filtering that removes the forced tool from the list while tool_choice still names it.","commonSituations":"Version skew between client tool names and server-registered tools; feature-flagged tool sets where the forced tool is disabled; typos in the tool name string.","solutions":["Remove tools (and mcp_servers) from the request when response_format.type is json_schema.","Or drop the json_schema response_format and instead define a tool with the desired schema and tool_choice forcing it (the classic function-calling way to get structured data).","Gate the two features on mutually exclusive configuration in the client."],"exampleFix":"# before\n{\"response_format\":{\"type\":\"json_schema\",...},\"tools\":[...]}\n\n# after\n{\"response_format\":{\"type\":\"json_schema\",...}}  # tools removed","handlingStrategy":"validation","validationCode":"if body.get('response_format', {}).get('type') == 'json_schema':\n    body.pop('tools', None); body.pop('mcp_servers', None)","typeGuard":"def json_schema_clean(body: dict) -> bool:\n    rf = body.get('response_format', {}).get('type')\n    return rf != 'json_schema' or (not body.get('tools') and not body.get('mcp_servers'))","tryCatchPattern":"except ValidationError as e:\n    if 'json_schema' in str(e):\n        body.pop('tools', None); retry()\n    else:\n        raise","preventionTips":["Model structured output and tools as mutually exclusive client modes","If you need schema-constrained tool calls, force a tool whose input schema IS your schema","Assert mode exclusivity in request-builder tests"],"tags":["validation","structured-output","tools","mutually-exclusive","chat-api"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}