parse_message() raises MessageParseError("Unknown message type: rate_limit_event") when the Claude Code CLI emits a rate_limit_event message. Because this exception is raised inside the receive_messages() async generator (at the yield parse_message(data) in client.py:187), it terminates the generator entirely. The caller can never receive any further messages. The session is effectively dead.
Reproduction
import asyncio
from claude_agent_sdk import ClaudeAgent, ClaudeAgentOptions
async def main():
options = ClaudeAgentOptions(workdir=".")
client = ClaudeAgent(options)
await client.connect()
await client.query("Hello")
async for message in client.receive_messages():
print(message)
# If the API returns a rate_limit_event during the stream,
# this raises MessageParseError and the generator dies.
# No further messages are ever received.
asyncio.run(main())
Root cause
message_parser.py has a strict allowlist of message types:
match message_type:
case "user": ...
case "assistant": ...
case "system": ...
case "result": ...
case "stream_event": ...
case _:
raise MessageParseError(f"Unknown message type: {message_type}", data)
The Claude Code CLI now emits rate_limit_event messages, which aren't in this list.
Impact
This is particularly severe because:
- The error occurs inside the yield expression in receive_messages(), which kills the async generator, and it cannot be resumed.
- Rate limit events are transient and informational. They should not be fatal.
- Any new message type added to the CLI in the future will trigger the same crash, making the SDK fragile against CLI updates.
Suggested fix
Two changes would make this robust:
- Add rate_limit_event as a recognized type in message_parser.py (with an appropriate dataclass).
- Make unknown types non-fatal for forward compatibility. Either:
- Return a generic UnknownMessage wrapper instead of raising, or
- Catch MessageParseError inside receive_messages() and skip/log the message:
async def receive_messages(self):
async for data in self._stream:
try:
msg = parse_message(data)
except MessageParseError:
continue
yield msg
Environment
- claude-agent-sdk==0.1.37
- Claude Code CLI 2.1.45
- Python 3.13.12
- macOS 15.5
Workaround
Monkey-patch parse_message to return None for unknown types and filter in the consumer:
import claude_agent_sdk._internal.message_parser as mp
_original = mp.parse_message
def _tolerant_parse(data):
try:
return _original(data)
except mp.MessageParseError as e:
if "Unknown message type" in str(e):
return None
raise
mp.parse_message = _tolerant_parse
# Also patch the client module's imported reference
import claude_agent_sdk.client as client_mod
if hasattr(client_mod, 'parse_message'):
client_mod.parse_message = _tolerant_parse
parse_message()raisesMessageParseError("Unknown message type: rate_limit_event")when the Claude Code CLI emits arate_limit_eventmessage. Because this exception is raised inside thereceive_messages()async generator (at theyield parse_message(data)in client.py:187), it terminates the generator entirely. The caller can never receive any further messages. The session is effectively dead.Reproduction
Root cause
message_parser.py has a strict allowlist of message types:
The Claude Code CLI now emits
rate_limit_eventmessages, which aren't in this list.Impact
This is particularly severe because:
Suggested fix
Two changes would make this robust:
Environment
Workaround
Monkey-patch parse_message to return None for unknown types and filter in the consumer: