Build1 publisher3 min readPublished
DeepSeek rejects the Codex turn where a resize notice separates a call from its output
Codex batched two view_image calls and put a resize notice between their outputs. OpenAI's Responses API pairs items by call ID wherever they sit. DeepSeek's endpoint wants them adjacent, and returns the same 400 on every later message.
The Engineer · Build desk

What happened
- A dev.to writeup reports Codex CLI and Codex Desktop returning HTTP 400 with "No tool output found for tool call call_01_..." against DeepSeek and other strict OpenAI-compatible providers.
- The session log shows Codex batching two view_image calls, then inserting an <image_resize_notice> developer message between the two function_call_output items after resizing one image.
- In all three failing threads both outputs were present and the rejection always named the second call, never the first.
- The author hit it three times on Codex Desktop, twice on September 17 and once on September 21, 2026.
- The remedy offered is prompt discipline: keep view_image alone in its turn, pre-shrink screenshots to viewport-only at 1500 px or narrower, and open a new thread to recover.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint Parallel tool batching is a throughput win for the client and a liveness hazard against an endpoint that enforces item order. The only lever in the writeup is asking the agent to call view_image alone.
- cost The unit of loss is a whole thread. Because the client replays the full history verbatim, every file, screenshot and decision established in that session has to be rebuilt somewhere else.
- decision Anyone swapping in a cheaper OpenAI-compatible endpoint now has to test item ordering as well as request schema, because a conversation one implementation accepts by call ID the other refuses on position.
- precedent A reasoning item triggers the same rejection as a developer message, so any client feature that slips a synthetic item in behind a tool output is a candidate for this failure on strict endpoints.
Three conditions have to line up. Codex has to batch two `view_image` calls into a single turn. At least one image has to trip the resize path, which keys off pixel dimensions and not file size [12]. And the provider has to require that a tool output sit directly after its own call [14]. Remove any one of the three and the turn goes through: with a single image, the notice lands after the output and nothing breaks [15].
The rollout log the author pulled out of `~/.codex/sessions` covers the whole sequence in 573 milliseconds [18][9]. Two `view_image` calls went out at 26.172 and 26.350 seconds, the output for the first at 26.376, the `<image_resize_notice>` developer message at 26.377, and the second output at 26.382 [10]. So the notice landed one millisecond after the first output and five milliseconds before the second [20]. The 400 came back at 26.745 [10].
Codex resends the full history on every turn, so that same ordering goes back out with each subsequent message and draws the same rejection against the same call ID [4][3]. Resuming the thread replays it [4]. "I typed something much less polite. Same error, same call ID," the author wrote [16].
Neither the model nor the image is involved. According to the issue the post cites, deepseek-ai/awesome-deepseek-integration#740, OpenAI's Responses API matches a `function_call` to its `function_call_output` by `call_id` wherever the two items sit in the list [13]. DeepSeek's Responses-compatible endpoint wants them adjacent, and the issue reproduces the difference cleanly: put a developer message or a reasoning item between a call and its output and you get the 400, keep them adjacent and you get a 200 [14]. The same conversation JSON is valid against one endpoint and invalid against the other.
The width rule needs a caveat before it transfers to your setup. Pre-shrinking to 1500 px wide keeps a capture under about 2.5 million pixels only while it stays under roughly 1,667 px tall [19]. A full-page render of a long document clears that at any sensible width, so the viewport-only half of the rule is what keeps the resize path from firing at all [5]. The threshold figure of roughly 2048 px, or about 2.5 million pixels, comes from CodexPlusPlus#2275 as quoted in the post [12].
The evidence is three dead threads from one user on Codex Desktop, configured with `model_provider = "deepseek"` and `wire_api = "responses"` [7][6], plus the reproduction in issue #740 [14]. The first hypothesis in the post, a dropped image output or an oversized file, did not survive the log: the image was 91 KB and was resized on pixel count, and both `function_call_output` items were present [8][11].
The call ID in the error message is enough to find the evidence. Running `grep -rl` for it across `~/.codex/sessions` returns the rollout JSONL, where the item order is readable in plain text [9]. The author has packaged the prompt rules as an agent skill for Codex and Claude Code, published as unstuck-qa [17].
What to watch
- Whether DeepSeek relaxes the adjacency requirement on its Responses-compatible endpoint, or Codex stops emitting the resize notice as a separate history item.
- Whether the same 400 reproduces on other OpenAI-compatible endpoints, which would move this beyond one user's three threads and one GitHub issue.
- Whether Codex gains a config option to cap parallel view_image calls, rather than leaving it to prompt rules.