Handle unknown event types gracefully instead of crashing#680
Open
Alan4506 wants to merge 1 commit intosmithy-lang:developfrom
Open
Handle unknown event types gracefully instead of crashing#680Alan4506 wants to merge 1 commit intosmithy-lang:developfrom
Alan4506 wants to merge 1 commit intosmithy-lang:developfrom
Conversation
alexgromero
reviewed
Apr 7, 2026
| logger.debug( | ||
| "Unknown event type: %s", member_name | ||
| ) | ||
| from smithy_core.shapes import ShapeID |
Contributor
There was a problem hiding this comment.
Should we move the ShapeID import to the top with the other smithy_core.shapes imports? Doesn't seem like we need it inline here.
Contributor
There was a problem hiding this comment.
We should add unit tests in test_deserializers.py for the unknown event handling path.
Also, the test fixture EventStreamDeserializer._consumer still raises SmithyError in the default case. Should that be updated to match the new behavior?
| result = self._deserializer(deserializer) | ||
| logger.debug("Successfully deserialized event: %s", result) | ||
| if isinstance(getattr(result, "value"), Exception): | ||
| if isinstance(getattr(result, "value", None), Exception): |
Contributor
There was a problem hiding this comment.
Suggested change
| if isinstance(getattr(result, "value", None), Exception): | |
| value = getattr(result, "value", None) | |
| if isinstance(value, Exception): |
Small readability suggestion (non-blocking): since only some variants have value, maybe assign it first and check that instead so it's a bit clearer and avoids looking up value twice here and in the raise statement.
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.
Background
The Smithy spec (streaming.html#client-behavior) states:
Currently, in
smithy-aws-event-streamdeserializers.py,EventDeserializer.read_struct()does a hard dictionary lookup (schema.members[member_name]) which raisesKeyErrorwhen the service sends an event type not present in the generated model. So we have to add some logic to handle unknown event types.Additionally, although smithy-python automatically creates unknown variants for streams, these variants only have a
tagfield unlike normal events that have avaluefield. WhenAWSEventReceiver.receive()callsgetattr(result, "value")without a default, it raisesAttributeErrorfor unknown variants.These were discovered during Q Business Chat streaming integration testing. The service sends
intermediateGroupEventandintermediateMessageEventevents not in any published SDK model, causing theasync for event in output_streamloop to crash.Reference implementations in other Smithy SDKs:
Both smithy-java and smithy-rs (Rust) already handle unknown event types gracefully:
smithy-java (
TestEventStream.java): Generates a$Unknown(String memberName)record for each event stream union. The builder has an$unknownMember(String memberName)method that the deserializer calls when it encounters an unrecognized event type. The unknown variant preserves the event type name.smithy-rs (
EventStreamUnmarshallerGenerator.kt): The generated unmarshaller has an_unknown_variantmatch arm that returnsOk(UnmarshalledMessage::Event(Output::Unknown))for client targets. Unlike Java, the Rust unknown variant does not preserve the event type name.This PR follows the smithy-java approach of preserving the event type name in the unknown variant's
tagfield, so users can identify which unmodeled event was received (e.g.,ChatOutputStreamUnknown(tag="intermediateGroupEvent")).Description of Changes
deserializers.py): Whenmember_nameis not inschema.members, construct a syntheticSchemawithmember_index=-1and call the consumer, which triggers the generatedcase _:branch inUnionGenerator.java.UnionGenerator.java): Thecase _:branch (previously just logging) now also constructs the per-union unknown variant with the event type name astag.aio/__init__.py): Changegetattr(result, "value")togetattr(result, "value", None)to preventAttributeErroron unknown variants.Testing
Regenerated all existing clients locally and all their integration tests passed. Also, verified with Q Business Chat streaming — unknown events (
intermediateGroupEvent,intermediateMessageEvent) are now handled gracefully instead of crashing. Users can identify unknown events viaisinstanceand access the event type name:By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.