From 3499639624e53110ee339ffcd0344ac42b928f58 Mon Sep 17 00:00:00 2001 From: shashvat-singham Date: Sun, 16 Aug 2026 14:13:32 +0530 Subject: [PATCH] Raise MessageParseError when the message field is not a dict parse_message wraps malformed input in MessageParseError -- non-dict data, a missing type, missing required fields all get the parser's own error type. But a "message" field that is not a dict escaped as a bare TypeError from indexing into it: parse_message({"type": "user", "message": "hi"}) # TypeError: string indices must be integers, not 'str' Same for the assistant branch. The existing handlers only catch KeyError, so TypeError/AttributeError from indexing a non-dict fell through, and a single malformed line from the CLI stream would surface as an unrelated-looking TypeError instead of the documented parse error. Catch TypeError/AttributeError alongside KeyError in both branches and raise MessageParseError with the offending data attached, like every other malformation. --- src/claude_agent_sdk/_internal/message_parser.py | 10 ++++++++++ tests/test_message_parser.py | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/src/claude_agent_sdk/_internal/message_parser.py b/src/claude_agent_sdk/_internal/message_parser.py index 931cc2a63..160bd745e 100644 --- a/src/claude_agent_sdk/_internal/message_parser.py +++ b/src/claude_agent_sdk/_internal/message_parser.py @@ -147,6 +147,11 @@ def parse_message(data: dict[str, Any]) -> Message | None: raise MessageParseError( f"Missing required field in user message: {e}", data ) from e + except (TypeError, AttributeError) as e: + # e.g. data["message"] is not a dict, so indexing into it fails + raise MessageParseError( + f"Malformed user message: {e}", data + ) from e case "assistant": try: @@ -222,6 +227,11 @@ def parse_message(data: dict[str, Any]) -> Message | None: raise MessageParseError( f"Missing required field in assistant message: {e}", data ) from e + except (TypeError, AttributeError) as e: + # e.g. data["message"] is not a dict, so indexing into it fails + raise MessageParseError( + f"Malformed assistant message: {e}", data + ) from e case "system": try: diff --git a/tests/test_message_parser.py b/tests/test_message_parser.py index e55fd1556..0962d3c6e 100644 --- a/tests/test_message_parser.py +++ b/tests/test_message_parser.py @@ -976,6 +976,13 @@ def test_parse_invalid_data_type(self): assert "Invalid message data type" in str(exc_info.value) assert "expected dict, got str" in str(exc_info.value) + def test_parse_non_dict_message_field(self): + """A non-dict 'message' field raises MessageParseError, not a bare TypeError.""" + for message_type in ("user", "assistant"): + with pytest.raises(MessageParseError) as exc_info: + parse_message({"type": message_type, "message": "not a dict"}) + assert f"Malformed {message_type} message" in str(exc_info.value) + def test_parse_missing_type_field(self): """Test that missing 'type' field raises MessageParseError.""" with pytest.raises(MessageParseError) as exc_info: