litellm - ✅(Solved) Fix Bedrock: document content blocks silently dropped during message conversion [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#24641Fetched 2026-04-08 01:37:26
View on GitHub
Comments
0
Participants
1
Timeline
11
Reactions
0
Timeline (top)
referenced ×8cross-referenced ×2labeled ×1

LiteLLM silently drops document content blocks (used for PDF support) when converting messages for Bedrock's Converse API. The same message works correctly with the native Anthropic API but fails with Bedrock.

Root Cause

_bedrock_converse_messages_pt() in litellm/litellm_core_utils/prompt_templates/factory.py only handles text, image, tool_use, and tool_result content block types. Document blocks are not processed.

Bedrock's Converse API does support document blocks via DocumentBlock: https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_DocumentBlock.html

Fix Action

Fixed

PR fix notes

PR #24644: fix(bedrock): handle document content blocks in Converse API message conversion

Description (problem / solution / changelog)

Relevant issues

Fixes #24641

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • 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

document content blocks (used for PDF support via Anthropic's API format) were silently dropped during Bedrock Converse API message conversion. The content block processing loop in _bedrock_converse_messages_pt() handled text, image_url, and file types but had no branch for document — blocks were skipped without any warning.

This meant sending a PDF to bedrock/anthropic.claude-* would result in the model responding as if no document was provided (~24 prompt tokens instead of ~47,000), while the same message worked correctly with anthropic/claude-*.

Root cause

The for element in message_block["content"] loop in three locations lacked an elif element["type"] == "document" branch:

  1. Sync user message processing in _bedrock_converse_messages_pt()
  2. Async user message processing in _bedrock_converse_messages_pt_async()
  3. Tool result conversion in _convert_to_bedrock_tool_call_result()

Fix

  • Added _process_document_message() static method on BedrockConverseMessagesProcessor that converts document content blocks to Bedrock's DocumentBlock format (extracting media_typeformat, datasource.bytes, and generating a deterministic document name using the same SHA-256 hashing pattern already used in _create_bedrock_block())
  • Added elif element["type"] == "document" branches in all three locations
  • All existing Bedrock types (DocumentBlock, SourceBlock, ContentBlock, ToolResultContentBlock) already supported documents — no type changes needed

Testing

Added 5 unit tests in tests/test_litellm/:

TestWhat it verifies
test_bedrock_converse_messages_pt_document_blockSingle document block produces correct BedrockContentBlock with format, source.bytes, and name
test_bedrock_converse_messages_pt_document_and_textMixed document + text content preserves both blocks (reproduces the exact scenario from #24641)
test_bedrock_converse_messages_pt_document_in_tool_resultDocument in tool result produces correct BedrockToolResultContentBlock
test_bedrock_converse_messages_pt_document_various_formatsMultiple media types (application/pdf, text/csv, text/html, OOXML) all produce correct format values
test_bedrock_converse_messages_pt_document_deterministic_nameSame document data always produces the same deterministic name

Reproduction script from the issue now passes:

import litellm.litellm_core_utils.prompt_templates.factory as factory

messages = [{"role": "user", "content": [
    {"type": "document", "source": {"type": "base64", "media_type": "application/pdf", "data": "dGVzdA=="}},
    {"type": "text", "text": "What is the title?"},
]}]

result = factory._bedrock_converse_messages_pt(messages, "anthropic.claude-sonnet-4-6", "bedrock")
print(result[0]["content"])
# Before: [{'text': 'What is the title?'}]                          — document dropped
# After:  [{'document': {'source': {'bytes': 'dGVzdA=='}, ...}},    — document preserved
#           {'text': 'What is the title?'}]

🤖 Generated with Claude Code

Changed files

  • litellm/litellm_core_utils/prompt_templates/factory.py (modified, +48/-0)
  • tests/test_litellm/litellm_core_utils/prompt_templates/test_litellm_core_utils_prompt_templates_factory.py (modified, +168/-1)

PR #24646: fix(bedrock): preserve document content blocks for Converse API (#24641)

Description (problem / solution / changelog)

Fixes #24641.\n\nLiteLLM currently drops document content blocks when converting messages to the Bedrock Converse API format because _bedrock_converse_messages_pt and _convert_to_bedrock_tool_call_result only process text, guarded_text, and image_url types. This prevents the model from accessing passed PDF attachments.\n\nThis patch explicitly checks for and passes through document type blocks by wrapping them into valid Bedrock Content structures, both for standard user messages and within tool results.

Changed files

  • litellm/litellm_core_utils/prompt_templates/factory.py (modified, +14/-0)

Code Example

import litellm.litellm_core_utils.prompt_templates.factory as factory

messages = [{"role": "user", "content": [
    {"type": "document", "source": {"type": "base64", "media_type": "application/pdf", "data": "dGVzdA=="}},
    {"type": "text", "text": "What is the title?"},
]}]

result = factory._bedrock_converse_messages_pt(messages, "anthropic.claude-sonnet-4-6", "bedrock")
print(result[0]["content"])
# Output: [{'text': 'What is the title?'}]
# Expected: should include document block

---

import asyncio
import base64
import litellm

pdf_base64 = base64.standard_b64encode(open("test.pdf", "rb").read()).decode()

messages = [{"role": "user", "content": [
    {"type": "document", "source": {"type": "base64", "media_type": "application/pdf", "data": pdf_base64}},
    {"type": "text", "text": "What is the title of this document?"},
]}]

# Works - model reads PDF correctly
response = await litellm.acompletion(model="anthropic/claude-sonnet-4-6", messages=messages, max_tokens=100)
print(response.usage.prompt_tokens)  # ~47000 tokens (includes PDF)

# Fails - model says "I don't see any document"
response = await litellm.acompletion(model="bedrock/anthropic.claude-sonnet-4-6", messages=messages, max_tokens=100)
print(response.usage.prompt_tokens)  # ~24 tokens (PDF dropped)
RAW_BUFFERClick to expand / collapse

Description

LiteLLM silently drops document content blocks (used for PDF support) when converting messages for Bedrock's Converse API. The same message works correctly with the native Anthropic API but fails with Bedrock.

Reproduction

Minimal test (no API call needed):

import litellm.litellm_core_utils.prompt_templates.factory as factory

messages = [{"role": "user", "content": [
    {"type": "document", "source": {"type": "base64", "media_type": "application/pdf", "data": "dGVzdA=="}},
    {"type": "text", "text": "What is the title?"},
]}]

result = factory._bedrock_converse_messages_pt(messages, "anthropic.claude-sonnet-4-6", "bedrock")
print(result[0]["content"])
# Output: [{'text': 'What is the title?'}]
# Expected: should include document block

With API call:

import asyncio
import base64
import litellm

pdf_base64 = base64.standard_b64encode(open("test.pdf", "rb").read()).decode()

messages = [{"role": "user", "content": [
    {"type": "document", "source": {"type": "base64", "media_type": "application/pdf", "data": pdf_base64}},
    {"type": "text", "text": "What is the title of this document?"},
]}]

# Works - model reads PDF correctly
response = await litellm.acompletion(model="anthropic/claude-sonnet-4-6", messages=messages, max_tokens=100)
print(response.usage.prompt_tokens)  # ~47000 tokens (includes PDF)

# Fails - model says "I don't see any document"
response = await litellm.acompletion(model="bedrock/anthropic.claude-sonnet-4-6", messages=messages, max_tokens=100)
print(response.usage.prompt_tokens)  # ~24 tokens (PDF dropped)

Expected Behavior

Document content blocks should be converted to Bedrock's DocumentBlock format and passed to the API.

Actual Behavior

Document blocks are silently dropped. The model only receives the text content.

Root Cause

_bedrock_converse_messages_pt() in litellm/litellm_core_utils/prompt_templates/factory.py only handles text, image, tool_use, and tool_result content block types. Document blocks are not processed.

Bedrock's Converse API does support document blocks via DocumentBlock: https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_DocumentBlock.html

Environment

  • LiteLLM version: 1.81.14
  • Python version: 3.13

Additional Context

This also affects document blocks in tool results (via _convert_to_bedrock_tool_call_result), not just user messages.

extent analysis

Fix Plan

To fix the issue, we need to modify the _bedrock_converse_messages_pt() function in litellm/litellm_core_utils/prompt_templates/factory.py to handle document content blocks. Here are the steps:

  • Update the function to check for document type in the content block
  • Convert the document block to Bedrock's DocumentBlock format
  • Add the converted DocumentBlock to the output

Example code:

def _bedrock_converse_messages_pt(messages, model, api):
    # ...
    for message in messages:
        for content in message["content"]:
            if content["type"] == "document":
                # Convert document block to Bedrock's DocumentBlock format
                document_block = {
                    "type": "document",
                    "content": content["source"]["data"],
                    "mediaType": content["source"]["media_type"]
                }
                # Add the converted DocumentBlock to the output
                output.append({"type": "document", "content": document_block})
            # ...
    return output

Additionally, we need to update the _convert_to_bedrock_tool_call_result function to handle document blocks in tool results.

Verification

To verify the fix, run the minimal test and API call examples provided in the issue body. The output should include the document block in the converted messages.

Extra Tips

  • Make sure to test the fix with different types of documents (e.g., PDF, Word, etc.) to ensure compatibility.
  • Consider adding error handling for cases where the document block is malformed or cannot be converted to Bedrock's DocumentBlock format.

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