claude-agent-sdk returns tool_result blocks in wrong order for parallel tool calls, causing API 400 errors

Resolved 💬 2 comments Opened Jan 30, 2026 by ningzio Closed Feb 28, 2026

Bug Description

When an agent makes parallel tool calls (e.g., calling 3 tools simultaneously: Grep, Glob, Glob), the claude-agent-sdk returns tool_result blocks in a different order than the original tool_use blocks. This causes Claude API to reject the request with a 400 error.

Error Message

API Error: 400 Expected toolResult blocks at messages.X.content for the following Ids:
<tool_use_id_1>, but found: <tool_use_id_3>

Environment

  • SDK Version: claude-agent-sdk 0.1.25
  • Python Version: 3.11
  • Platform: macOS (Darwin 25.2.0)

Root Cause

The SDK returns tool results in the order they complete rather than the order they were requested. Claude API strictly requires tool_result blocks to match the exact order of tool_use blocks as specified in the API documentation.

Reproduction Steps

  1. Create a ClaudeSDKClient with a workspace
  2. Send a query that triggers the agent to call 2+ tools in parallel (e.g., "explore the codebase structure")
  3. Observe the tool_result order in the response messages doesn't match tool_use order
  4. API returns 400 error

Example from Logs

Tool Use Order (Correct)

tool_use_id: tooluse_Gb5TE--nToOsbVVYZ6NXDw  (Grep - first)
tool_use_id: tooluse_6XF_ZDjJRC-Bc1kb7df3rg  (Glob - second)
tool_use_id: tooluse_ObcxhMsfSqqImPWofLkTng  (Glob - third)

Tool Result Order (Incorrect)

tool_result: tooluse_ObcxhMsfSqqImPWofLkTng  ❌ (third tool, returned first)
tool_result: tooluse_Gb5TE--nToOsbVVYZ6NXDw  ✓  (first tool, returned second)
tool_result: tooluse_6XF_ZDjJRC-Bc1kb7df3rg  ✓  (second tool, returned third)

API Error

API Error: 400 Expected toolResult blocks at messages.10.content for the following Ids:
tooluse_Gb5TE--nToOsbVVYZ6NXDw, but found: tooluse_ObcxhMsfSqqImPWofLkTng

Complete Error Logs

<details>
<summary>Full server logs showing the issue</summary>

DEBUG:sse_starlette.sse:chunk: b'event: tool_use\r\ndata: {"name": "Grep", ...}, "tool_use_id": "tooluse_Gb5TE--nToOsbVVYZ6NXDw"}\r\n\r\n'
DEBUG:sse_starlette.sse:chunk: b'event: tool_use\r\ndata: {"name": "Glob", ...}, "tool_use_id": "tooluse_6XF_ZDjJRC-Bc1kb7df3rg"}\r\n\r\n'
DEBUG:sse_starlette.sse:chunk: b'event: tool_use\r\ndata: {"name": "Glob", ...}, "tool_use_id": "tooluse_ObcxhMsfSqqImPWofLkTng"}\r\n\r\n'
DEBUG:sse_starlette.sse:chunk: b'event: tool_result\r\ndata: {"tool_use_id": "tooluse_ObcxhMsfSqqImPWofLkTng", ...}\r\n\r\n'
DEBUG:sse_starlette.sse:chunk: b'event: tool_result\r\ndata: {"tool_use_id": "tooluse_Gb5TE--nToOsbVVYZ6NXDw", ...}\r\n\r\n'
DEBUG:sse_starlette.sse:chunk: b'event: tool_result\r\ndata: {"tool_use_id": "tooluse_6XF_ZDjJRC-Bc1kb7df3rg", ...}\r\n\r\n'
DEBUG:sse_starlette.sse:chunk: b'event: text\r\ndata: {"content": "API Error: 400 Expected toolResult blocks at messages.10.content for the following Ids: tooluse_Gb5TE--nToOsbVVYZ6NXDw, but found: tooluse_ObcxhMsfSqqImPWofLkTng"}\r\n\r\n'

</details>

Expected Behavior

The SDK should maintain and return tool_result blocks in the same order as tool_use blocks, regardless of which tools complete first.

Suggested Fix

The SDK should:

  1. Track the original order of tool_use blocks when the assistant makes parallel tool calls
  2. Buffer completed tool_result blocks as they arrive
  3. Reorder them to match the tool_use order before constructing the user message
  4. Send the properly ordered results to the Claude API

Workaround

None currently available. There's no CLI flag or SDK option to:

  • Disable parallel tool execution
  • Force sequential tool execution
  • Manually control tool result ordering

Impact

This bug makes the SDK unusable for any agent workflows that involve parallel tool calls, which is a common pattern in:

  • Code exploration tasks
  • File search operations
  • Multi-source data gathering

The agent fails with API 400 errors whenever it attempts to optimize performance by calling multiple tools in parallel.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗