litellm - ✅(Solved) Fix Responses API → Bedrock Converse: assistant message has toolUse before text, causing 400 error [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
BerriAI/litellm#24361Fetched 2026-04-08 01:18:13
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Participants
Timeline (top)
closed ×1cross-referenced ×1labeled ×1referenced ×1

Error Message

BedrockException - messages.1: tool_use ids were found without tool_result blocks immediately after: tooluse_xxx. Each tool_use block must have a corresponding tool_result block in the next message.

Root Cause

The Bedrock Converse API request constructed by LiteLLM has the toolUse block before the text block in the assistant message:

msg[0] role=user       -> [text, text]
msg[1] role=assistant  -> [toolUse, text]     <- wrong order
msg[2] role=user       -> [toolResult]

Bedrock requires all text blocks to appear before any toolUse blocks within an assistant message. The correct order should be:

msg[1] role=assistant  -> [text, toolUse]     <- correct order

Because toolUse comes first, Bedrock interprets the text block as breaking the toolUse -> toolResult pairing and rejects the request.

Fix Action

Fix / Workaround

  • #22946 - same content block ordering issue, fixed for /v1/messages pass-through in #23104, but not for the Responses API -> Bedrock Converse path
  • #23105 - same error for Vertex AI Claude via Responses API, fixed by #23116 for parallel tool calls but not for content block ordering
  • #15178 - duplicate tool call IDs (different root cause, already fixed)

PR fix notes

PR #24368: fix(bedrock): sort assistant content blocks so text precedes toolUse

Description (problem / solution / changelog)

Relevant issues

Fixes https://github.com/berriAI/litellm/issues/24361

Pre-Submission checklist

  • I have Added testing in the tests/test_litellm/ directory, Adding at least 1 test is a hard requirement - see details
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Type

🐛 Bug Fix

Changes

When the Responses API (/v1/responses) routes to Bedrock Converse, multi-turn tool calling fails on Claude Sonnet 4 and Haiku 3.5+ because toolUse content blocks appear before text blocks in assistant messages.

The Responses API converts function_call and message output items into separate consecutive assistant messages. The Bedrock Converse transformer merges these into one message, but preserves input order. If function_call came before message, the merged result is [toolUse, text] — Claude rejects this with:

"tool_use ids were found without tool_result blocks immediately after"

Add _sort_bedrock_assistant_content_blocks() that reorders content blocks within assistant messages: reasoningContenttexttoolUse. Applied in both sync and async Bedrock Converse transformation paths, after the existing deduplication step.

Tests added

  • test_sort_bedrock_assistant_content_blocks_text_before_tooluse — direct unit test
  • test_sort_bedrock_assistant_content_blocks_reasoning_first — reasoning ordering
  • test_sort_bedrock_assistant_content_blocks_preserves_order_when_correct — no-op when correct
  • test_bedrock_converse_sorts_text_before_tooluse_sync — integration test through sync path

Changed files

  • litellm/litellm_core_utils/prompt_templates/factory.py (modified, +36/-0)
  • tests/litellm_core_utils/test_bedrock_converse_dedup_factory.py (modified, +131/-0)

PR #25853: fix(bedrock): handle orphaned tool blocks caused by conversation compaction

Description (problem / solution / changelog)

Summary

Fixes Bedrock Converse API failures when clients like OpenAI Codex CLI compact long conversations. Compaction truncates history, leaving behind orphaned toolUse/toolResult blocks that Bedrock rejects.

Errors fixed:

  • "tool_use ids were found without tool_result blocks"
  • "The toolConfig field must be defined when using toolUse and toolResult content blocks."
  • "tool_choice.type: Field required" (follow-on from injected toolConfig missing toolChoice)

Related issues: #25669, #24361

Changes

All fixes are gated on modify_params=True and follow existing LiteLLM patterns.

1. litellm/utils.pyhas_tool_call_blocks()

Extended to detect Anthropic-format content blocks (type="tool_use" / type="tool_result") and role="tool" messages, in addition to the existing OpenAI tool_calls array check. Previously, when a Responses API request arrived with Anthropic-format tool content, the function returned False and _transform_request_helper skipped injecting toolConfig.

2. litellm/litellm_core_utils/prompt_templates/factory.py

Applied to both _bedrock_converse_messages_pt (sync) and _bedrock_converse_messages_pt_async (async):

a. Sort assistant content blocks (inside loop, after deduplication): Ensures order reasoningContent → text → toolUse within each assistant message. Bedrock rejects requests where text blocks appear after toolUse blocks, as it interprets them as breaking the toolUse→toolResult pairing.

b. Tool pairing sanitization (post-loop):

  • Pass 1: For each assistant message with orphaned toolUse blocks (no matching toolResult), collect all orphaned IDs in order, then inject dummy toolResult blocks as a single batch into the next user message (or a newly inserted user message). Batch injection is important — injecting one at a time via prepend reverses the order, and Bedrock requires toolResult order to match toolUse order.
  • Pass 2: Remove toolResult blocks whose toolUseId has no matching toolUse in any assistant message. If a user message becomes empty, replace its content with [BedrockContentBlock(text=" ")] (single space — Bedrock rejects empty strings).

3. litellm/llms/bedrock/chat/converse_transformation.py

Applied to both _transform_request (sync) and _async_transform_request (async):

After building bedrock_messages, if tool blocks are now present (injected by fix #2) but toolConfig is absent (because the original OpenAI messages had no tool blocks, so _transform_request_helper never added it), inject a dummy toolConfig with:

  • A single ToolBlock(toolSpec=...) with empty input schema
  • toolChoice=ToolChoiceValuesBlock(auto={}) — required by Bedrock/Claude; omitting it causes "tool_choice.type: Field required"

Test plan

  • Verify no regression on normal tool-calling requests (tools present in original messages)
  • Verify compacted conversations with orphaned toolUse no longer hit "tool_use ids were found without tool_result blocks"
  • Verify compacted conversations with orphaned toolResult have them silently removed
  • Verify toolConfig is injected when tool blocks exist after compaction sanitization
  • Verify assistant messages with multiple parallel tool calls inject toolResult blocks in correct order

🤖 Generated with Claude Code

Changed files

  • litellm/litellm_core_utils/prompt_templates/factory.py (modified, +457/-814)
  • litellm/llms/bedrock/chat/converse_transformation.py (modified, +60/-0)
  • litellm/utils.py (modified, +15/-0)
  • tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py (modified, +260/-0)

Code Example

BedrockException - messages.1: `tool_use` ids were found without `tool_result` blocks
immediately after: tooluse_xxx. Each `tool_use` block must have a corresponding
`tool_result` block in the next message.

---

msg[0] role=user       -> [text, text]
msg[1] role=assistant  -> [toolUse, text]     <- wrong order
msg[2] role=user       -> [toolResult]

---

msg[1] role=assistant  -> [text, toolUse]     <- correct order

---

curl -X POST https://bedrock-runtime.us-west-2.amazonaws.com/model/us.anthropic.claude-opus-4-6-v1/converse-stream
RAW_BUFFERClick to expand / collapse

What happened?

When using the Responses API (/v1/responses) with a Bedrock Claude model, multi-turn tool calling fails on the second turn. The first turn (tool call) succeeds, but sending the tool result back fails with:

BedrockException - messages.1: `tool_use` ids were found without `tool_result` blocks
immediately after: tooluse_xxx. Each `tool_use` block must have a corresponding
`tool_result` block in the next message.

Root Cause

The Bedrock Converse API request constructed by LiteLLM has the toolUse block before the text block in the assistant message:

msg[0] role=user       -> [text, text]
msg[1] role=assistant  -> [toolUse, text]     <- wrong order
msg[2] role=user       -> [toolResult]

Bedrock requires all text blocks to appear before any toolUse blocks within an assistant message. The correct order should be:

msg[1] role=assistant  -> [text, toolUse]     <- correct order

Because toolUse comes first, Bedrock interprets the text block as breaking the toolUse -> toolResult pairing and rejects the request.

Steps to reproduce

  1. Configure LiteLLM proxy with a Bedrock Claude model
  2. Use any client that sends requests to /v1/responses with tools (e.g., OpenAI Codex Desktop)
  3. First turn succeeds - model returns a tool call
  4. Second turn (with tool result) fails with 400

How I verified this

Enabled --detailed_debug on the proxy and captured the raw POST request sent to Bedrock:

curl -X POST https://bedrock-runtime.us-west-2.amazonaws.com/model/us.anthropic.claude-opus-4-6-v1/converse-stream

The request payload shows:

  • msg[0] role=user: [text, text]
  • msg[1] role=assistant: [toolUse(id=tooluse_xxx), text(73 chars)] - toolUse before text
  • msg[2] role=user: [toolResult(id=tooluse_xxx)]

Environment

  • LiteLLM version: 1.82.6
  • Provider: bedrock/us.anthropic.claude-opus-4-6-v1
  • Client: Codex Desktop (uses /v1/responses)
  • modify_params: true and drop_params: true enabled - does not fix it

Related issues

  • #22946 - same content block ordering issue, fixed for /v1/messages pass-through in #23104, but not for the Responses API -> Bedrock Converse path
  • #23105 - same error for Vertex AI Claude via Responses API, fixed by #23116 for parallel tool calls but not for content block ordering
  • #15178 - duplicate tool call IDs (different root cause, already fixed)

extent analysis

Fix Plan

To fix the issue, we need to reorder the content blocks in the assistant message to ensure that text blocks appear before toolUse blocks.

Here are the steps to fix the issue:

  • Modify the LiteLLM proxy to reorder the content blocks in the assistant message.
  • Specifically, move the toolUse block after the text block in the assistant message.

Example code snippet:

def reorder_content_blocks(message):
    # Separate text and toolUse blocks
    text_blocks = [block for block in message if block['type'] == 'text']
    tool_use_blocks = [block for block in message if block['type'] == 'toolUse']

    # Reorder the blocks to put text blocks first
    reordered_message = text_blocks + tool_use_blocks

    return reordered_message

# Apply the reordering function to the assistant message
assistant_message = reorder_content_blocks(assistant_message)

Verification

To verify that the fix worked, you can:

  • Enable --detailed_debug on the proxy and capture the raw POST request sent to Bedrock.
  • Check that the toolUse block appears after the text block in the assistant message.
  • Test the Responses API with a tool call and verify that the second turn succeeds.

Extra Tips

  • Make sure to test the fix with different tool calls and client configurations to ensure that it works in all scenarios.
  • Consider adding a test case to the LiteLLM test suite to prevent regressions.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING