From d23afd95b1de472043003e2dc859ccf1fb0bbf6c Mon Sep 17 00:00:00 2001 From: Dickson Tsai Date: Fri, 23 Jan 2026 06:14:22 +0000 Subject: [PATCH] fix: read error field from top-level data, not message object The error field in CLI output is at the top level of the JSON, not inside the message object. The previous fix (PR #405) incorrectly read from data["message"].get("error") instead of data.get("error"). CLI output structure shows error at top level: ```json { "type": "assistant", "message": { ... }, "error": "unknown" // error is at top level } ``` Fixes #505 Co-Authored-By: Claude Opus 4.5 --- .../_internal/message_parser.py | 2 +- tests/test_message_parser.py | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/claude_agent_sdk/_internal/message_parser.py b/src/claude_agent_sdk/_internal/message_parser.py index 4bfe8145..e0ed58e3 100644 --- a/src/claude_agent_sdk/_internal/message_parser.py +++ b/src/claude_agent_sdk/_internal/message_parser.py @@ -123,7 +123,7 @@ def parse_message(data: dict[str, Any]) -> Message: content=content_blocks, model=data["message"]["model"], parent_tool_use_id=data.get("parent_tool_use_id"), - error=data["message"].get("error"), + error=data.get("error"), ) except KeyError as e: raise MessageParseError( diff --git a/tests/test_message_parser.py b/tests/test_message_parser.py index cd18952e..2b28d103 100644 --- a/tests/test_message_parser.py +++ b/tests/test_message_parser.py @@ -233,6 +233,54 @@ def test_parse_assistant_message_inside_subagent(self): assert isinstance(message, AssistantMessage) assert message.parent_tool_use_id == "toolu_01Xrwd5Y13sEHtzScxR77So8" + def test_parse_assistant_message_with_error(self): + """Test parsing an assistant message with error field (issue #505). + + The error field is at the top-level of the JSON, not inside the message object. + This enables applications to detect API errors like rate limits. + """ + data = { + "type": "assistant", + "message": { + "content": [{"type": "text", "text": "API Error: 404 ..."}], + "model": "", + }, + "session_id": "test-session", + "uuid": "test-uuid", + "error": "unknown", # error is at top level, not inside message + } + message = parse_message(data) + assert isinstance(message, AssistantMessage) + assert message.error == "unknown" + + def test_parse_assistant_message_with_rate_limit_error(self): + """Test parsing an assistant message with rate_limit error.""" + data = { + "type": "assistant", + "message": { + "content": [{"type": "text", "text": "Rate limit exceeded"}], + "model": "", + }, + "error": "rate_limit", + } + message = parse_message(data) + assert isinstance(message, AssistantMessage) + assert message.error == "rate_limit" + + def test_parse_assistant_message_with_auth_error(self): + """Test parsing an assistant message with authentication_failed error.""" + data = { + "type": "assistant", + "message": { + "content": [{"type": "text", "text": "Invalid API key"}], + "model": "", + }, + "error": "authentication_failed", + } + message = parse_message(data) + assert isinstance(message, AssistantMessage) + assert message.error == "authentication_failed" + def test_parse_valid_result_message(self): """Test parsing a valid result message.""" data = {