<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Karl Ji</title>
    <description>The latest articles on DEV Community by Karl Ji (@kar23232).</description>
    <link>https://dev.to/kar23232</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4137436%2Fc4882cb2-c7a4-433c-a9e3-7a2ea31db229.png</url>
      <title>DEV Community: Karl Ji</title>
      <link>https://dev.to/kar23232</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kar23232"/>
    <language>en</language>
    <item>
      <title>Codex + DeepSeek: why "No tool output found for tool call" kills your session (and how to avoid it)</title>
      <dc:creator>Karl Ji</dc:creator>
      <pubDate>Tue, 22 Sep 2026 10:51:06 +0000</pubDate>
      <link>https://dev.to/kar23232/codex-deepseek-why-no-tool-output-found-for-tool-call-kills-your-session-and-how-to-avoid-it-2dkc</link>
      <guid>https://dev.to/kar23232/codex-deepseek-why-no-tool-output-found-for-tool-call-kills-your-session-and-how-to-avoid-it-2dkc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error:&lt;/strong&gt; &lt;code&gt;No tool output found for tool call call_01_...&lt;/code&gt; (HTTP 400, &lt;code&gt;invalid_request_error&lt;/code&gt;) in &lt;strong&gt;Codex CLI / Codex Desktop&lt;/strong&gt; with &lt;strong&gt;DeepSeek&lt;/strong&gt; or another strict OpenAI-compatible provider.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cause:&lt;/strong&gt; Codex batched two &lt;code&gt;view_image&lt;/code&gt; calls. After resizing a large image, it inserted an &lt;code&gt;&amp;lt;image_resize_notice&amp;gt;&lt;/code&gt; developer message &lt;strong&gt;between&lt;/strong&gt; the two &lt;code&gt;function_call_output&lt;/code&gt; items. DeepSeek's Responses API expects each output to directly follow its call, so it rejected the request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it never recovers:&lt;/strong&gt; the broken turn stays in the thread history, so every later message fails with the &lt;strong&gt;same call ID&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workaround:&lt;/strong&gt; make &lt;code&gt;view_image&lt;/code&gt; the only tool call in its turn, and pre-shrink screenshots (viewport-only, ≤1500 px wide). Start a new thread to recover.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ready-made rules:&lt;/strong&gt; I packaged all of this as an agent skill for Codex and Claude Code: &lt;strong&gt;&lt;a href="https://github.com/Kar23232/unstuck-qa" rel="noopener noreferrer"&gt;https://github.com/Kar23232/unstuck-qa&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The error
&lt;/h2&gt;

&lt;p&gt;If you're here, you've probably seen this in Codex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No tool output found for tool call call_01_HcX4jELNhOOdX0zqGayn0609.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It usually appears right after the agent says something like &lt;em&gt;"Viewed 2 images"&lt;/em&gt;. After that, every message you send returns the exact same error.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I ran into it
&lt;/h2&gt;

&lt;p&gt;I use &lt;strong&gt;Codex Desktop&lt;/strong&gt; with &lt;strong&gt;DeepSeek&lt;/strong&gt; as the model provider (&lt;code&gt;model_provider = "deepseek"&lt;/code&gt;, &lt;code&gt;wire_api = "responses"&lt;/code&gt;). I was doing QA work: rendering document pages to PNG to check the layout, and screenshotting a web app to reproduce bugs.&lt;/p&gt;

&lt;p&gt;Mid-task, the agent looked at two images at once. Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No tool output found for tool call call_01_UISHMq0wlN4CLWt3E6Wa2694.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I typed "?". Same error. I typed something much less polite. Same error, same call ID. The thread was dead.&lt;/p&gt;

&lt;p&gt;It happened in &lt;strong&gt;three separate threads&lt;/strong&gt;: twice on September 17 and once on September 21, 2026.&lt;/p&gt;

&lt;p&gt;My first guess, and the first explanation an AI assistant gave me, was that the provider was dropping image outputs, or that the image was too big. The image was only 91 KB, so size seemed ruled out. &lt;strong&gt;Both guesses were wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the rollout logs
&lt;/h2&gt;

&lt;p&gt;Codex saves every thread as JSONL under:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Search for the failing call ID to find the right file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rl&lt;/span&gt; &lt;span class="s2"&gt;"call_01_HcX4"&lt;/span&gt; ~/.codex/sessions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the timeline around the failure (timestamps in seconds, image payloads removed):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;26.172  function_call          view_image  call_00_…  page-1.png
26.350  function_call          view_image  call_01_…  page-2.png
26.376  function_call_output              call_00_…
26.377  message (developer)    &amp;lt;image_resize_notice&amp;gt; …
26.382  function_call_output              call_01_…
26.382  message (developer)    &amp;lt;image_resize_notice&amp;gt; …
26.745  ❌ 400 No tool output found for tool call call_01_…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things stood out, and they were identical in all three dead threads:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Both outputs exist.&lt;/strong&gt; Nothing was lost. &lt;code&gt;call_01&lt;/code&gt; has its &lt;code&gt;function_call_output&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A developer message sits between them.&lt;/strong&gt; Codex inserted an &lt;code&gt;&amp;lt;image_resize_notice&amp;gt;&lt;/code&gt; right after output #1, so it landed between output #1 and output #2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It always fails on the second call&lt;/strong&gt; (&lt;code&gt;call_01_…&lt;/code&gt;), never the first.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;About the 91 KB: resizing depends on &lt;strong&gt;pixel dimensions, not file size&lt;/strong&gt;. A small PNG of a tall rendered page can still go over the limit. &lt;a href="https://github.com/BigPizzaV3/CodexPlusPlus/issues/2275" rel="noopener noreferrer"&gt;CodexPlusPlus#2275&lt;/a&gt; mentions images over roughly 2048 px or about 2.5 million pixels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root cause: strict adjacency meets an inserted notice
&lt;/h2&gt;

&lt;p&gt;In the Responses API, a conversation is a list of items: &lt;code&gt;function_call&lt;/code&gt;, &lt;code&gt;function_call_output&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;, &lt;code&gt;reasoning&lt;/code&gt;, and so on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI's Responses API&lt;/strong&gt; pairs a &lt;code&gt;function_call&lt;/code&gt; with its &lt;code&gt;function_call_output&lt;/code&gt; by &lt;code&gt;call_id&lt;/code&gt;, wherever they sit in the list (as described in &lt;a href="https://github.com/deepseek-ai/awesome-deepseek-integration/issues/740" rel="noopener noreferrer"&gt;deepseek-ai/awesome-deepseek-integration#740&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepSeek's Responses-compatible endpoint&lt;/strong&gt; requires the output to come &lt;strong&gt;directly after&lt;/strong&gt; its call. Issue #740 reproduces this 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 200.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now add Codex's resize behavior. When an image in a tool output gets resized, Codex appends an &lt;code&gt;&amp;lt;image_resize_notice&amp;gt;&lt;/code&gt; developer message after that output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ One image: fine                    ❌ Two images in parallel: rejected
function_call          A              function_call          A
function_call_output   A              function_call          B
developer: resize notice              function_call_output   A
                                      developer: resize notice   ← breaks adjacency
                                      function_call_output   B   ← "No tool output found"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With one image, the notice comes after the output and nothing breaks. With two parallel images, the notice for image A lands between the two outputs, and DeepSeek decides &lt;code&gt;call_01&lt;/code&gt; was never answered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why the thread is wedged forever:&lt;/strong&gt; Codex resends the full history on every turn, so the same malformed sequence goes out every time and gets the same 400. Resuming the thread replays the same history, so it fails too.&lt;/p&gt;

&lt;h2&gt;
  
  
  A second path to the same error
&lt;/h2&gt;

&lt;p&gt;The resize notice isn't the only trigger. Other people have documented related paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/openai/codex/issues/44604" rel="noopener noreferrer"&gt;openai/codex#44604&lt;/a&gt;:&lt;/strong&gt; the next request is sent &lt;strong&gt;before the last tool output of a batch is appended&lt;/strong&gt;. Reported when &lt;code&gt;view_image&lt;/code&gt; is batched with more images (about a 70 ms gap) or with a command that exceeds the 30-second tool wait.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/farion1231/cc-switch/issues/7569" rel="noopener noreferrer"&gt;farion1231/cc-switch#7569&lt;/a&gt;:&lt;/strong&gt; the proxy's media-lift feature inserts a synthetic user message mid-batch when &lt;code&gt;view_image&lt;/code&gt; runs in parallel with &lt;code&gt;exec_command&lt;/code&gt; or MCP tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/BigPizzaV3/CodexPlusPlus/issues/2275" rel="noopener noreferrer"&gt;BigPizzaV3/CodexPlusPlus#2275&lt;/a&gt;:&lt;/strong&gt; when translating to Chat Completions, the resize notice ends up between &lt;code&gt;tool&lt;/code&gt; messages, and the upstream rejects the request with &lt;code&gt;Messages with role 'tool' must be a response to a preceding message with 'tool_calls'&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common thread: &lt;strong&gt;an image sharing a batch with other tool calls, plus a provider that enforces strict ordering.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Are you hitting this? Quick checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✔️ Codex CLI or Codex Desktop with DeepSeek, or another OpenAI-compatible provider or proxy&lt;/li&gt;
&lt;li&gt;✔️ The failing ID looks like &lt;code&gt;call_01_…&lt;/code&gt; (the second call of a batch)&lt;/li&gt;
&lt;li&gt;✔️ It happened right after "Viewed 2 images", or after &lt;code&gt;view_image&lt;/code&gt; ran alongside another tool&lt;/li&gt;
&lt;li&gt;✔️ Every later message fails with the &lt;strong&gt;same&lt;/strong&gt; call ID&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If most of these match, it's very likely this bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workarounds
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Make images go alone.&lt;/strong&gt; &lt;code&gt;view_image&lt;/code&gt; should be the only tool call in its turn: never two images at once, and never an image batched with a command. You can put this in &lt;code&gt;AGENTS.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Never call view_image in parallel with any other tool call. One image per turn.
&lt;span class="p"&gt;-&lt;/span&gt; Before viewing an image, downscale it to ≤1500 px wide. Use viewport screenshots, not full-page captures.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Shrink images before the agent looks at them,&lt;/strong&gt; so Codex never needs to insert a resize notice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# macOS (limits the longest side to 1500 px)&lt;/span&gt;
sips &lt;span class="nt"&gt;-s&lt;/span&gt; format jpeg &lt;span class="nt"&gt;-Z&lt;/span&gt; 1500 shot.png &lt;span class="nt"&gt;--out&lt;/span&gt; shot.jpg

&lt;span class="c"&gt;# ImageMagick (only shrinks if wider than 1500 px)&lt;/span&gt;
magick shot.png &lt;span class="nt"&gt;-resize&lt;/span&gt; &lt;span class="s1"&gt;'1500x&amp;gt;'&lt;/span&gt; shot.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For very tall pages, take several viewport screenshots instead of one full-page capture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Recover a wedged thread.&lt;/strong&gt; Start a new thread; retrying and resuming both replay the broken history. To avoid losing work, have the agent keep a &lt;code&gt;progress.md&lt;/code&gt; that records what it has finished, so the new thread can continue from there. A more surgical option (described in &lt;a href="https://github.com/farion1231/cc-switch/issues/7569" rel="noopener noreferrer"&gt;cc-switch#7569&lt;/a&gt;) is to delete the orphaned call/output items from the rollout JSONL. Back the file up first, since this is unofficial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Or switch providers.&lt;/strong&gt; According to #740, OpenAI's Responses API pairs by &lt;code&gt;call_id&lt;/code&gt;, so this ordering shouldn't break there. I haven't tested that myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  I turned this into a skill: unstuck-qa 🔓
&lt;/h2&gt;

&lt;p&gt;After losing three threads, I wrote the rules down as an agent skill: &lt;strong&gt;&lt;a href="https://github.com/Kar23232/unstuck-qa" rel="noopener noreferrer"&gt;unstuck-qa&lt;/a&gt;&lt;/strong&gt;. It works in both Codex and Claude Code.&lt;/p&gt;

&lt;p&gt;On top of the two rules above, it covers the other ways an agent gets stuck while testing web apps in a real browser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💬 &lt;strong&gt;Native dialogs:&lt;/strong&gt; registers a &lt;code&gt;confirm()&lt;/code&gt; / &lt;code&gt;alert()&lt;/code&gt; handler before clicking, so clicks don't hang forever&lt;/li&gt;
&lt;li&gt;⏱️ &lt;strong&gt;No &lt;code&gt;networkidle&lt;/code&gt; waits:&lt;/strong&gt; waits for specific elements with timeouts, which matters on pages that poll in the background&lt;/li&gt;
&lt;li&gt;💾 &lt;strong&gt;One click, one verdict&lt;/strong&gt; for save actions: no endless "refresh and try again" loops&lt;/li&gt;
&lt;li&gt;📒 &lt;strong&gt;A progress log,&lt;/strong&gt; so a dead thread doesn't mean starting over&lt;/li&gt;
&lt;li&gt;🧪 &lt;strong&gt;Skip the UI when possible:&lt;/strong&gt; unit or API checks take about 10× fewer tool calls than clicking around&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Codex&lt;/span&gt;
git clone https://github.com/Kar23232/unstuck-qa ~/.codex/skills/unstuck-qa

&lt;span class="c"&gt;# Claude Code&lt;/span&gt;
git clone https://github.com/Kar23232/unstuck-qa ~/.claude/skills/unstuck-qa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What would fix it properly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Codex:&lt;/strong&gt; emit resize notices after the whole batch of outputs, and validate call/output pairing right before sending (see &lt;a href="https://github.com/openai/codex/issues/46193" rel="noopener noreferrer"&gt;openai/codex#46193&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proxies&lt;/strong&gt; (cc-switch, CodexPlusPlus and similar): reorder items so every output directly follows its call before forwarding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepSeek:&lt;/strong&gt; pair calls and outputs by &lt;code&gt;call_id&lt;/code&gt;, the same way OpenAI's Responses API does (&lt;a href="https://github.com/deepseek-ai/awesome-deepseek-integration/issues/740" rel="noopener noreferrer"&gt;#740&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related issues
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/openai/codex/issues/44604" rel="noopener noreferrer"&gt;openai/codex#44604&lt;/a&gt;: next request sent before the last tool output is appended&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/openai/codex/issues/46193" rel="noopener noreferrer"&gt;openai/codex#46193&lt;/a&gt;: pairing only enforced when history is rebuilt, not at send time&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/deepseek-ai/awesome-deepseek-integration/issues/740" rel="noopener noreferrer"&gt;deepseek-ai/awesome-deepseek-integration#740&lt;/a&gt;: DeepSeek requires adjacent call/output&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/farion1231/cc-switch/issues/7190" rel="noopener noreferrer"&gt;farion1231/cc-switch#7190&lt;/a&gt;: &lt;code&gt;image_resize_notice&lt;/code&gt; inserted between tool results&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/farion1231/cc-switch/issues/7569" rel="noopener noreferrer"&gt;farion1231/cc-switch#7569&lt;/a&gt;: parallel &lt;code&gt;view_image&lt;/code&gt; + other tools&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/BigPizzaV3/CodexPlusPlus/issues/2275" rel="noopener noreferrer"&gt;BigPizzaV3/CodexPlusPlus#2275&lt;/a&gt;: resize notice breaks &lt;code&gt;tool&lt;/code&gt; message order&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;If your Codex thread keeps answering every message with &lt;code&gt;No tool output found for tool call&lt;/code&gt;, nothing is wrong with your files. A notice got wedged between two tool results, and the thread will never recover on its own. Start fresh, keep images alone, shrink them first, and you shouldn't see it again.&lt;/p&gt;

&lt;p&gt;If this saved your afternoon, a ⭐ on &lt;a href="https://github.com/Kar23232/unstuck-qa" rel="noopener noreferrer"&gt;unstuck-qa&lt;/a&gt; helps the next person find it. Found another trigger? Open an issue there.&lt;/p&gt;

</description>
      <category>agentskills</category>
      <category>deepseek</category>
      <category>openai</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
