Summary
parse_message raises an uncaught TypeError when an assistant message has content that is a plain string, or a content list containing a non-dict element. The user branch already handles the string case, so the behavior is asymmetric. Because the TypeError is not wrapped in MessageParseError, it escapes parse_message and tears down the receive_messages() / query() async generator (same failure mode as the rate_limit_event reports #583/#601/#603 and the missing-signature reports #339/#949). Anthropic-compatible backends are a common trigger, since they often emit content as a bare string.
Reproduction (verified on latest main)
from claude_agent_sdk._internal.message_parser import parse_message
parse_message({"type": "assistant", "message": {"model": "m", "content": "hi"}})
# -> TypeError: string indices must be integers, not 'str'
parse_message({"type": "assistant", "message": {"model": "m", "content": ["oops"]}})
# -> TypeError: string indices must be integers, not 'str'
parse_message({"type": "user", "message": {"content": "hi"}}) # control
# -> UserMessage(content="hi")
Root cause: the assistant branch iterates data["message"]["content"] directly (message_parser.py around line 130) and indexes block["type"], with no isinstance list check and no isinstance(block, dict) guard. The user branch (around line 86) has both.
Expected
- A string
content parses into a single TextBlock, matching the user branch.
- A non-dict block raises the documented
MessageParseError, not a raw TypeError.
Environment
claude-agent-sdk: main (also reproduces on installed releases); Python 3.11
A fix with regression tests is up in #1058.
Summary
parse_messageraises an uncaughtTypeErrorwhen anassistantmessage hascontentthat is a plain string, or acontentlist containing a non-dict element. Theuserbranch already handles the string case, so the behavior is asymmetric. Because theTypeErroris not wrapped inMessageParseError, it escapesparse_messageand tears down thereceive_messages()/query()async generator (same failure mode as the rate_limit_event reports #583/#601/#603 and the missing-signature reports #339/#949). Anthropic-compatible backends are a common trigger, since they often emitcontentas a bare string.Reproduction (verified on latest
main)Root cause: the
assistantbranch iteratesdata["message"]["content"]directly (message_parser.py around line 130) and indexesblock["type"], with noisinstancelist check and noisinstance(block, dict)guard. Theuserbranch (around line 86) has both.Expected
contentparses into a singleTextBlock, matching theuserbranch.MessageParseError, not a rawTypeError.Environment
claude-agent-sdk: main (also reproduces on installed releases); Python 3.11
A fix with regression tests is up in #1058.