-
Notifications
You must be signed in to change notification settings - Fork 1k
Raise MessageParseError (not TypeError) on malformed field types #988
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -122,6 +122,10 @@ def parse_message(data: dict[str, Any]) -> Message | None: | |
| raise MessageParseError( | ||
| f"Missing required field in user message: {e}", data | ||
| ) from e | ||
| except TypeError as e: | ||
| raise MessageParseError( | ||
| f"Malformed field in user message: {e}", data | ||
| ) from e | ||
|
|
||
| case "assistant": | ||
| try: | ||
|
|
@@ -184,6 +188,10 @@ def parse_message(data: dict[str, Any]) -> Message | None: | |
| raise MessageParseError( | ||
| f"Missing required field in assistant message: {e}", data | ||
| ) from e | ||
| except TypeError as e: | ||
| raise MessageParseError( | ||
| f"Malformed field in assistant message: {e}", data | ||
| ) from e | ||
|
|
||
| case "system": | ||
| try: | ||
|
|
@@ -242,6 +250,10 @@ def parse_message(data: dict[str, Any]) -> Message | None: | |
| raise MessageParseError( | ||
| f"Missing required field in system message: {e}", data | ||
| ) from e | ||
| except TypeError as e: | ||
| raise MessageParseError( | ||
| f"Malformed field in system message: {e}", data | ||
| ) from e | ||
|
Comment on lines
+253
to
+256
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point on test coverage parity. The three added regression tests target the originally reported rate_limit_event regression plus the two most commonly malformed branches (user/assistant, since their message field is what CLI payloads vary on most). The system/result/stream_event branches are wrapped symmetrically for defense-in-depth (the same TypeError -> MessageParseError shape, with original data attached), so behaviorally they are covered by the same contract the existing tests assert. Happy to extend coverage to those branches too if the maintainers prefer one test per branch — the 753-pass suite stays green either way. |
||
|
|
||
| case "result": | ||
| try: | ||
|
|
@@ -275,6 +287,10 @@ def parse_message(data: dict[str, Any]) -> Message | None: | |
| raise MessageParseError( | ||
| f"Missing required field in result message: {e}", data | ||
| ) from e | ||
| except TypeError as e: | ||
| raise MessageParseError( | ||
| f"Malformed field in result message: {e}", data | ||
| ) from e | ||
|
|
||
| case "stream_event": | ||
| try: | ||
|
|
@@ -288,6 +304,10 @@ def parse_message(data: dict[str, Any]) -> Message | None: | |
| raise MessageParseError( | ||
| f"Missing required field in stream_event message: {e}", data | ||
| ) from e | ||
| except TypeError as e: | ||
| raise MessageParseError( | ||
| f"Malformed field in stream_event message: {e}", data | ||
| ) from e | ||
|
|
||
| case "rate_limit_event": | ||
| try: | ||
|
|
@@ -310,6 +330,10 @@ def parse_message(data: dict[str, Any]) -> Message | None: | |
| raise MessageParseError( | ||
| f"Missing required field in rate_limit_event message: {e}", data | ||
| ) from e | ||
| except TypeError as e: | ||
| raise MessageParseError( | ||
| f"Malformed field in rate_limit_event message: {e}", data | ||
| ) from e | ||
|
|
||
| case _: | ||
| # Forward-compatible: skip unrecognized message types so newer | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair concern on TypeError breadth. The scope here is intentionally narrow: each except TypeError sits inside the same small try block that already catches KeyError for the same parsing step, so it only wraps the dict subscripting / unpacking of CLI payload fields — not arbitrary downstream logic. This mirrors the existing KeyError -> MessageParseError pattern in the file (symmetric handling for the two ways a malformed payload can fail). Pre-validating shapes per branch would work too, but it would expand the diff considerably and duplicate checks the dataclass constructors already perform. Re-raising as MessageParseError with the original data preserves both the original TypeError (via 'from e') and the malformed payload for debugging, so genuine programmer errors remain inspectable in tracebacks.