From 8fbc6a5c91a9188d9c83e812cbbb7a8ca8fb4c10 Mon Sep 17 00:00:00 2001 From: saadkhaleeq610 Date: Sun, 17 May 2026 14:10:40 +0500 Subject: [PATCH] fix(anthropic): handle missing text field in content_block_start chunks Some Anthropic-compatible providers send content_block_start events for text blocks without the optional 'text' field, causing a KeyError crash. Use .get('text', '') so streams from these providers don't break. Fixes #28067 --- litellm/llms/anthropic/chat/handler.py | 2 +- .../chat/test_anthropic_chat_handler.py | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/litellm/llms/anthropic/chat/handler.py b/litellm/llms/anthropic/chat/handler.py index 2fb29b32a61e..bf7f7593e695 100644 --- a/litellm/llms/anthropic/chat/handler.py +++ b/litellm/llms/anthropic/chat/handler.py @@ -820,7 +820,7 @@ def chunk_parser(self, chunk: dict) -> ModelResponseStream: # noqa: PLR0915 "type" ] if content_block_start["content_block"]["type"] == "text": - text = content_block_start["content_block"]["text"] + text = content_block_start["content_block"].get("text", "") elif ( content_block_start["content_block"]["type"] == "tool_use" or content_block_start["content_block"]["type"] == "server_tool_use" diff --git a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_handler.py b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_handler.py index 2fdd639e74d4..43cd4897320a 100644 --- a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_handler.py +++ b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_handler.py @@ -1013,6 +1013,26 @@ def test_current_content_block_type_tracking(): assert iterator.current_content_block_type is None +def test_content_block_start_text_field_missing(): + """ + Some Anthropic-compatible providers emit content_block_start for text blocks + without the optional "text" field: {"type": "text"} instead of {"type": "text", "text": ""}. + chunk_parser should not raise KeyError and should treat it as an empty string. + Regression test for https://github.com/BerriAI/litellm/issues/28067 + """ + iterator = ModelResponseIterator( + streaming_response=MagicMock(), sync_stream=True, json_mode=False + ) + chunk = { + "type": "content_block_start", + "index": 0, + "content_block": {"type": "text"}, # "text" field intentionally absent + } + # should not raise KeyError + response = iterator.chunk_parser(chunk=chunk) + assert response.choices[0].delta.content == "" + + def test_web_search_tool_result_captured_in_provider_specific_fields(): """ Test that web_search_tool_result content is captured in provider_specific_fields.