tool_search call on a strict Responses provider fails with 400 missing field `call_id` on the follow-up request
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of the Codex App are you using (From “About Codex” dialog)?
26.901.51231 (macOS). Bundled Codex core: codex-cli 0.153.4.
What subscription do you have?
No ChatGPT subscription for inference on this profile — the app runs against a third-party Responses-compatible provider: DeepSeek (api.deepseek.com, wire API = responses), model deepseek-flash, API key auth.
What platform is your computer?
macOS (Apple silicon), Darwin 25.x.
What issue are you seeing?
tool_search is unusable on this provider configuration: as soon as the model emits a tool_search call, the follow-up request is rejected with a strict-schema 400, so the turn (and every retry of it) fails before any tool result is produced.
{"error":{"message":"Failed to deserialize the JSON body into the target type: input: missing field `call_id` at line 1 column 73159","type":"invalid_request_error","param":null,"code":"invalid_request_error"}}
Four independent reproductions, all failing in well under one second, with a near-constant offset in the serialized body (which suggests the malformed item sits at a fixed position near the tool_search_call entry):
| # | prompt | reported column |
|---|---|---|
| 1 | ask for two tool_search calls in one turn |
73278 |
| 2 | ask for two tool_search calls in one turn (no plugin mention) |
73159 |
| 3 | ask for a single tool_search call |
72894 |
| 4 | ask for a single tool_search call, explicitly no other tool use |
73061 |
The malformed item never reaches the local rollout: the thread's persisted history contains the user/developer messages and the task_started/task_complete events only, i.e. the item with the missing call_id exists on the wire request that the provider rejects. This matches the client-side nature of the other call_id reports listed below.
This is distinct from the existing call_id issues: all of the ones I could find involve function_call_output injected by automations, or normal-thread resume:
- #44723, #44519, #41690, #42067, #42088, #43515 — automations / standalone
function_call_output/ resume paths - #20574 —
tool_searchon non-native endpoints fails differently (unsupported payload, Ollama/Bifrost) - #26379 — malformed
tool_search_callarguments on resume (different field)
I could not find one that covers "model calls tool_search normally, no automation involved, on a custom Responses provider".
What steps can reproduce the bug?
- Configure a custom provider that validates the Responses schema strictly, e.g. DeepSeek with
wire_api = "responses". - Start a fresh thread (project or projectless) and send a minimal prompt that leads the model to call
tool_search, e.g.:
Call tool_search once with query "libtv doctor target_project list_projects" and report the namespace you get back. Do not use any other tool. - The first sampling request completes, the model returns the
tool_searchcall, and the follow-up request immediately fails with the error above. - Retrying the turn reproduces it identically.
Session ids (sanitized): 01a08fb4-e274-7d21-aa86-6c2e349a083a, 01a08fb5-0b4d-7371-9d92-c8fc2866d9b3, 01a08fb5-3196-7e70-abf0-44ef611bcce4, 01a08fb7-1b7d-7cd1-85fa-3ebcf65ad83a.
What is the expected behavior?
The tool_search call is serialized with a call_id (as required by the Responses schema), the search result is returned to the model, and the turn proceeds. Alternatively, if tool_search cannot be supported on this provider configuration, the feature should be disabled/omitted instead of emitting a request that can never be accepted.
What is the actual behavior?
Every thread that calls tool_search dies on the first follow-up request with missing field call_id. Because the failure happens during request construction, no tool_search_output is ever produced and no workaround exists inside the thread; starting a new thread only helps until a tool_search call happens again.
Additional information
- Same Core version with a different provider (
deepseek-flashreplaced by a ChatGPT-side model in the same app) servedtool_searchsuccessfully earlier the same day in this install, so the item shape that strict providers reject appears to be provider-specific. - Local feature flags report
tool_searchandtool_search_always_defer_mcp_toolsasremovedwhile both are clearly still active in this build, in case that is relevant to routing this report. - Happy to attach the four rollout JSONL files (sanitized) or run an instrumented build if that helps isolate where the
call_idis dropped.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the tool_search follow-up request construction and Responses-schema serialization for custom providers. Reproduce with a strict Responses-compatible provider such as DeepSeek and inspect the serialized tool_search_call entry. Done means the follow-up includes call_id and reaches tool_search_output, or tool_search is omitted when unsupported.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- api, cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 56/100