diff --git a/litellm/llms/anthropic/chat/handler.py b/litellm/llms/anthropic/chat/handler.py index 2fb29b32a61..9d027d6fb6f 100644 --- a/litellm/llms/anthropic/chat/handler.py +++ b/litellm/llms/anthropic/chat/handler.py @@ -820,7 +820,13 @@ class ModelResponseIterator: "type" ] if content_block_start["content_block"]["type"] == "text": - text = content_block_start["content_block"]["text"] + # Anthropic Messages streaming spec: the initial text on a + # content_block_start text block is conventionally "" and the + # real content arrives via subsequent content_block_delta + # chunks. Some Anthropic-compatible upstreams omit the field + # entirely rather than sending "", so default to "" to avoid + # aborting the stream with KeyError. + 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/llm_translation/test_anthropic_completion.py b/tests/llm_translation/test_anthropic_completion.py index 371b27c5b21..cc3eebdf000 100644 --- a/tests/llm_translation/test_anthropic_completion.py +++ b/tests/llm_translation/test_anthropic_completion.py @@ -262,6 +262,25 @@ def test_anthropic_tool_streaming(): assert tool_use["index"] == correct_tool_index +def test_anthropic_content_block_start_text_missing_field(): + """ + Regression for #28067: some Anthropic-compatible upstreams omit the + optional `text` field on a content_block_start text block. The actual + content arrives via subsequent content_block_delta chunks, so the parser + must tolerate the missing field instead of raising KeyError and aborting + the stream. + """ + response_iter = ModelResponseIterator([], False) + chunk = { + "type": "content_block_start", + "index": 0, + # 'text' field intentionally omitted (observed in the wild) + "content_block": {"type": "text"}, + } + # Should not raise. + response_iter.chunk_parser(chunk=chunk) + + def test_process_anthropic_headers_empty(): result = process_anthropic_headers({}) assert result == {}, "Expected empty dictionary for no input"