Repository navigation
[BUG] Image read_file combined with other tool calls produces Anthropic 400 error #1774
Description
Describe the bug
When the model calls read_file on an image (JPG/PNG) in the same turn as another tool call, Zoo Code builds the next user message with the image as a standalone top-level image block placed between the tool_result blocks, instead of nesting it inside the read_file tool_result's content array. The Anthropic API requires all tool_result blocks to be contiguous at the start of the message, so it stops scanning at the image block and rejects the request:
400 {"type":"error","error":{"type":"invalid_request_error","message":"messages.16: `tool_use` ids were found without `tool_result` blocks immediately after: toolu_01UsrBMcBxFtm2TQQ1e2iCQb. Each `tool_use` block must have a corresponding `tool_result` block in the next message."}}
The malformed message is persisted to api_conversation_history.json, so every Retry replays the same broken history and the task is permanently stuck. Starting a new task reproduces it as soon as the model reads an image alongside another tool call again.
Actual message shape written to disk (from ~/Library/Application Support/Code/User/globalStorage/zoocodeorganization.zoo-code/tasks/<id>/api_conversation_history.json, message index 16, base64 elided):
{
"role": "user",
"content": [
{ "type": "tool_result", "tool_use_id": "toolu_01HnYZ1DVtTfKgouvT5frb2P",
"content": "File: ../…/river-and-sun-WORKING.jpg\nNote: Image file (219 KB)" },
{ "type": "image", "source": { "type": "base64", "media_type": "image/jpeg", "data": "<base64 …>" } },
{ "type": "tool_result", "tool_use_id": "toolu_01UsrBMcBxFtm2TQQ1e2iCQb",
"content": "Command executed in terminal … Exit code: 0 …" },
{ "type": "text", "text": "<environment_details>…" }
]
}Note both tool_result blocks are present — the API error is misleading; the real issue is the image sibling breaking contiguity.
To Reproduce
Steps to reproduce the behavior:
- Use Anthropic provider (Claude) in Code mode, with native tool calling / multiple tool calls per turn enabled.
- Have an image file available (e.g.
logo.jpg) and set auto-approve for read + execute (or approve both manually — approval state does not matter). - Prompt: "In a single response, call
read_fileonlogo.jpgand also runexecute_commandwithls." - Both tools execute successfully and results appear in the UI.
- The next API request fails with the 400 above. Retry fails identically; the task can no longer continue.
Also reproduced with two image reads plus a third tool call in one turn (message shape [tool_result, tool_result, image, tool_result, image, text…]).
Expected behavior
The image should be nested inside the corresponding tool_result's content array, per the Anthropic Messages API spec:
{ "type": "tool_result", "tool_use_id": "toolu_01HnYZ…",
"content": [
{ "type": "text", "text": "File: …/logo.jpg\nNote: Image file (219 KB)" },
{ "type": "image", "source": { "type": "base64", "media_type": "image/jpeg", "data": "…" } }
] }All tool_result blocks should then be contiguous at the start of the user message, followed by any text blocks. Manually rewriting the on-disk history this way (moving each image into the preceding tool_result.content) fixed the task immediately, confirming the diagnosis.
Additionally, a retry should not replay a message the API has already rejected as structurally invalid; ideally the history should be validated/repaired before resend.
Screenshots
Screenshot of error taken later. The original error had the 400 error described above.
Video
N/A — deterministic, reproducible with the steps above.
What version of zoo are you running
Zoo Code 3.82.2 (zoocodeorganization.zoo-code-3.82.2)
VS Code 26.6.2, macOS 26.6.2 (25G83)
Provider: Anthropic, model claude-fable-5-1, Code mode
Additional context
- Only occurs when an image
read_fileis combined with at least one other tool call in the same assistant turn. A lone image read works because theimageblock ends up after the onlytool_result, so contiguity is preserved. - Files read were outside the workspace (iCloud Drive), but that's incidental — the approval prompt is not involved.
- Workaround for users: instruct the model not to read image files, or to read images in their own turn with no other tool calls; or paste the image into the chat instead.
- Recovery for a stuck task: close the task, edit
api_conversation_history.json, move each top-levelimageblock into thecontentarray of the precedingtool_result(converting a stringcontentto[{"type":"text","text":…}]first), reopen the task and retry. - Likely location: the code path that assembles
tool_resultblocks forread_fileimage results when multiple tool uses are being combined into one user message (image blocks appended as siblings rather than as tool_result content). - Likely dupe of [BUG]Tool results interleaved with image blocks break Anthropic API (tool_use without immediate tool_result) #1307

Activity
PierrunoYT commentedon Sep 28, 2026
Working on this!
PierrunoYT commentedon Sep 28, 2026
Thanks for the precise report and the recovery steps. As you noted, this is the same bug as #1307. Two PRs together cover both parts of this issue:
tool_resultis added, image blocks already in the message are moved after it, so new messages come out as[tool_result, tool_result, image, text].tool_resultblocks are moved to the front. A task already stuck with the broken shape on disk then recovers on its next retry, without editingapi_conversation_history.json. Stored history isn't changed.