openai / openai/codex

tool_search exposes deferred tools with an empty schema, permanently breaking threads on strict Responses providers (DeepSeek)

Open
#45,585 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app bug custom-model tool-calls
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

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 CLI 0.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 custom models.json catalog from the DeepSeek integration guide
  • Browser / node_repl MCP server enabled
Steps to reproduce
  1. Use a custom Responses provider (DeepSeek) in the Desktop app.
  2. Let the agent call tool_search with a query that matches a deferred tool — e.g. "automation" (matches codex_app::automation_update), or a query that matches deferred MCP tools such as mcp__node_repl::js.
  3. 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_search call 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
  • #37786 — automation_update root oneOf / type: null on DeepSeek (eager-loaded path)
  • #39848, #36441 — same error class on other strict providers

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the tool_search result construction into the follow-up Responses request, focusing on how deferred app and MCP tools are represented. Reproduce the DeepSeek request with a deferred tool, then verify that discovered tools carry their real schema or a valid object schema and that subsequent turns no longer fail.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, backend-api-design
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
66/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.