fix(streaming): add direct type-map fallback for raw dict events#1287
Open
gambletan wants to merge 1 commit intoanthropics:mainfrom
Open
fix(streaming): add direct type-map fallback for raw dict events#1287gambletan wants to merge 1 commit intoanthropics:mainfrom
gambletan wants to merge 1 commit intoanthropics:mainfrom
Conversation
…hropics#941) When the union discriminator deserialization in construct_type_unchecked silently returns a raw dict instead of a typed BaseModel (observed in some environments and pydantic versions), accumulate_event now falls back to a direct lookup table keyed on the 'type' field to construct the correct event model. This ensures well-formed content_block_delta events (and all other RawMessageStreamEvent variants) are always promoted to their typed BaseModel even if the generic Annotated-union deserialization path fails. Fixes: anthropics#941 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #941 —
content_block_deltaSSE events fail to deserialize with"Unexpected event runtime type, after deserialising twice"in some environments.Root cause
accumulate_eventin_messages.py(and_beta_messages.py) receives events fromStream[RawMessageStreamEvent]. In certain environments (older pydantic versions, or edge cases in the Annotated-union discriminator path),construct_type_uncheckedsilently returns the raw dict instead of a typedBaseModel. The previous code retried once then raisedTypeError.Fix
Add a third-tier fallback: if both the initial
isinstancecheck and theconstruct_type_uncheckedretry fail to produce aBaseModel, look up the event's"type"field in an explicitdict[str, type[BaseModel]]map and callmodel_constructdirectly. This guarantees that any well-formed event dict (includingcontent_block_delta) is always promoted to the correct typed object.The same fix is applied to the beta messages streaming path (
_beta_messages.py).Changes
src/anthropic/lib/streaming/_messages.py— import concrete event classes, add_RAW_EVENT_TYPE_MAP, add fallback inaccumulate_eventsrc/anthropic/lib/streaming/_beta_messages.py— same for the beta pathtests/lib/streaming/test_messages.py— regression test that passes a raw dict event directly toaccumulate_eventand asserts it succeedsTest plan
test_accumulate_event_handles_raw_dict_content_block_deltapasses raw dict events toaccumulate_eventand asserts they are handled correctlytests/lib/streaming/— 26 tests)🤖 Generated with Claude Code