Repository navigation
Description
What happened?
On Codex Desktop with a custom provider that uses wire_api = "responses" (DeepSeek's official endpoint), a thread works normally until the model calls the built-in tool_search tool. From that point on every turn in that thread fails with:
Invalid schema for function 'codex_app::automation_update': schema must be a JSON Schema of 'type: "object"', got 'type: null'.
This looks related to the automation_update schema reports (#37786, #39848, #36441) but the trigger is different: in this build automation_update is deferred (deferLoading: true), it is not part of the initial tool manifest, and the request only starts failing after tool_search returns it. The failure then sticks for the rest of the thread.
Environment
- Codex Desktop app
26.818.61809, bundled CLI0.149.0-alpha.4.3 - macOS 15.6.1 (arm64)
model_provider = "deepseek",base_url = "https://api.deepseek.com/",wire_api = "responses",model = "deepseek-v4-flash"with the custommodels.jsoncatalog from the DeepSeek integration guide- Browser /
node_replMCP server enabled
Steps to reproduce
- Use a custom Responses provider (DeepSeek) in the Desktop app.
- Let the agent call
tool_searchwith a query that matches a deferred tool — e.g."automation"(matchescodex_app::automation_update), or a query that matches deferred MCP tools such asmcp__node_repl::js. - The very next sampling request fails with the 400 above. All following turns in the same thread fail the same way.
Observed locally: thread A failed at 10:24:08, 10:25:06, 10:25:24, 10:26:52; a second thread failed at 10:27:31 and 10:28:16 — same error every time, always right after a tool_search call.
Evidence
The tool_search result item reports the matched tools with inputSchema: null, for both app tools and MCP tools:
[
{"type":"namespace","name":"mcp__node_repl","tools":[
{"name":"js","inputSchema":null},{"name":"js_reset","inputSchema":null}]},
{"type":"namespace","name":"codex_app","tools":[
{"name":"automation_update","inputSchema":null},{"name":"open_in_codex","inputSchema":null}]}
]Minimal payloads sent straight to https://api.deepseek.com/responses:
| tool payload | result |
|---|---|
namespace tool, "parameters": {} |
the exact error above |
namespace tool, "parameters": null |
accepted |
| namespace tool, normal object schema | accepted |
flat function named codex_app::automation_update |
rejected earlier, for the name pattern — so the flat form is not what is being sent |
So the follow-up request appears to carry parameters: {} for tools that were discovered through tool_search, and DeepSeek's schema validation rejects the whole request because of it. Note that automation_update is only the first reported tool because the namespace is validated in order; the same request also contains schema-less MCP tools.
Expected behavior
Tools surfaced by tool_search should carry their real JSON schema, or at minimum a valid placeholder such as {"type": "object", "properties": {}}, so that strict OpenAI-compatible providers accept the request.
Impact
- One
tool_searchcall permanently bricks the thread on strict providers: every later turn fails before the model can answer. - Not recoverable from the prompt side; the user has to abandon the thread.
- Affects any custom Responses provider that validates tool schemas (DeepSeek, and presumably other strict OpenAI-compatible endpoints).
Workaround
A local proxy in front of the provider that rewrites an empty parameters to {"type": "object", "properties": {}, "additionalProperties": true} makes the identical request succeed (validated end-to-end, including streaming), which confirms the empty schema is the only problem. That is a client-side workaround, not a fix.
Related
- Codex Desktop: automation_update schema (root oneOf, type null) 400s on strict providers like DeepSeek (Responses API) #37786 —
automation_updaterootoneOf/type: nullon DeepSeek (eager-loaded path) - automation_update tool schema is rejected by strict OpenAI-compatible providers #39848, [Bug] codex_app__automation_update schema type is null - causes DeepSeek HTTP 400 via CC Switch #36441 — same error class on other strict providers
Activity
wenlinl commentedon Sep 15, 2026
Correction after more digging on the current build (Desktop
26.818.61809, CLI0.149.0-alpha.4.3): the schema that reaches the provider is not empty — it is the app's real Zod-generatedautomation_updateschema (draft 2020-12), whose root isoneOf+$defswith no roottype— i.e. the same shape as #37786.What is specific to this report is the delivery path: on this build
automation_updateis deferred (deferLoading: true), so it never appears in the initial tool manifest; the request only breaks oncetool_searchreturns it, and from then on the thread stays broken on every turn.Payload matrix against
https://api.deepseek.com/responses(namespace toolcodex_app/automation_update,defer_loading: true):parametersoneOf, notype)schema must be a JSON Schema of 'type: "object"', got 'type: null'"type": "object"(oneOf/$defsuntouched)oneOf→anyOf+ roottype{}{"type":"object","properties":{}}So the minimal fix on the client side is to ensure the root of a function tool schema is an object schema — adding
"type": "object"is sufficient; nestedoneOf,$refand$defsare accepted by DeepSeek. A local proxy that does exactly this (plus a placeholder for truly empty schemas) makes all of the above work, which is how I confirmed it.wenlinl commentedon Sep 15, 2026
Update: root cause confirmed on this side, with a validated client-side workaround.
Environment. Codex Desktop
26.818.61809/ CLI0.149.0-alpha.4.3, macOS 15.6.1, customdeepseekprovider (wire_api = "responses",model = "deepseek-v4-flash").What actually breaks. The schema that reaches the provider is the app's real Zod-generated
automation_updateschema (draft 2020-12): root isoneOf+$defswith no roottype. DeepSeek requires the root of a function-tool schema to be an object schema and rejects the entire request otherwise. Becauseautomation_updateis deferred on this build, the request only starts failing aftertool_searchreturns the tool, and the thread then stays broken on every later turn.Payload matrix (namespace tool
codex_app/automation_update,defer_loading: true, againstapi.deepseek.com/responses):parametersoneOf, notype)got 'type: null'"type": "object"(oneOf/$defsuntouched)oneOf→anyOf+ roottype{}{"type":"object","properties":{}}Workaround that fixed it here. A loopback proxy in front of the provider base URL that:
tools[], namespaced tools, and tool definitions embedded in conversation items) and adds a root"type": "object"to any tool schema that lacks one, while leavingoneOf/$defsintact; andInvalid schema for function '<name>'.Result. The thread that had failed on six consecutive turns resumes normally. Since applying it: 27 consecutive provider requests returned
200, zero schema errors, no other client change.Suggested proper fix. Emit an object root for tool schemas (adding
"type": "object"is sufficient; nestedoneOf/$ref/$defsare accepted), and/or do not lose the schema when a deferred tool is re-exposed aftertool_search.