openai / openai/codex

tool_search call on a strict Responses provider fails with 400 missing field `call_id` on the follow-up request

Open
#44,779 1 comment 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 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_search on non-native endpoints fails differently (unsupported payload, Ollama/Bifrost)
  • #26379 — malformed tool_search_call arguments 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?
  1. Configure a custom provider that validates the Responses schema strictly, e.g. DeepSeek with wire_api = "responses".
  2. 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.
  3. The first sampling request completes, the model returns the tool_search call, and the follow-up request immediately fails with the error above.
  4. 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-flash replaced by a ChatGPT-side model in the same app) served tool_search successfully 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_search and tool_search_always_defer_mcp_tools as removed while 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_id is dropped.

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 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.