fix: preserve additional top-level properties on AirbyteStateMessage - #1134
Conversation
Co-Authored-By: bot_apk <apk@cognition.ai>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
👋 Greetings, Airbyte Team Member!Here are some helpful tips and reminders for your convenience. 💡 Show Tips and TricksTesting This CDK VersionYou can test this version of the CDK using the following: # Run the CLI from this branch:
uvx 'git+https://github.com/airbytehq/airbyte-python-cdk.git@devin/1787726398-preserve-state-message-additional-properties#egg=airbyte-python-cdk[dev]' --help
# Update a connector to use the CDK from this branch ref:
cd airbyte-integrations/connectors/source-example
poe use-cdk-branch devin/1787726398-preserve-state-message-additional-propertiesPR Slash CommandsAirbyte Maintainers can execute the following slash commands on your PR:
|
There was a problem hiding this comment.
Pull request overview
This PR fixes a protocol serialization bug in the Python CDK where unknown top-level keys on AirbyteStateMessage (notably the platform-attached dynamic id) were being silently dropped during a load → dump round trip, breaking destinations on platform 1.7+ that require the id to be echoed back.
Changes:
- Introduces a
CustomType(AirbyteStateMessageType) to preserve and round-trip unknown top-level state-message properties via anadditional_propertiesattribute. - Updates the global
custom_type_resolversoAirbyteStateMessagealways uses the new custom type (including when nested underAirbyteMessage). - Adds regression tests covering STREAM and GLOBAL state round-trips, plus direct state-message serializer behavior and the “no leakage when no extras” case.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| unit_tests/test_airbyte_protocol_serializers.py | Adds regression tests asserting unknown top-level properties (e.g., "id") survive load→dump for state messages. |
| airbyte_cdk/models/airbyte_protocol_serializers.py | Adds AirbyteStateMessageType and updates custom_type_resolver to preserve unknown top-level keys on AirbyteStateMessage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Summary
Python-CDK destinations on platform 1.7+ fail with
java.lang.IllegalStateException: State message does not contain idbecause the platform attaches a dynamicidto each source STATE message (as an additional property) and requires it on the state messages the destination echoes back — butAirbyteStateMessageis a plain dataclass serialized with serpyco-rs, which silently drops unknown top-level keys on aload/dumpround trip.AirbyteStateBlobalready preserves extras via aCustomType;AirbyteStateMessagedid not.This adds
AirbyteStateMessageType(CustomType[AirbyteStateMessage, Dict[str, Any]])inairbyte_protocol_serializers.py:deserialize: loads known fields with an inner serializer (blob-only resolver to avoid recursion), then stores any unknown top-level keys on the instance asadditional_properties.serialize: dumps known fields, then mergesadditional_propertiesback (never overwriting known keys).custom_type_resolvernow resolvesAirbyteStateMessage→AirbyteStateMessageType, so bothAirbyteMessageSerializerandAirbyteStateMessageSerializerpreserve extras.The
AirbyteStateMessagedataclass and its public fields are unchanged; when a message has no extra keys, output is byte-identical to before.Regression tests (
unit_tests/test_airbyte_protocol_serializers.py) assert a STATE message with an extra"id": 42survives load→dump for STREAM state, GLOBAL state, and the direct state serializer, and that noadditional_propertieskey leaks when there are no extras. All four fail without the fix (3 round-trip failures verified).Context / prior art:
extra=allow, preservedid) to >=7.7.0 (serpyco dataclasses, dropsid), breaking all syncs: https://github.com/airbytehq/oncall/issues/13391 (this affects every Python-CDK destination on CDK ≥6, e.g. milvus/pinecone/qdrant/weaviate/chroma/astra/typesense).Follow-up: once released, bump destination-milvus (and siblings) to a CDK version containing this fix.
Requested via
/ai-fixon the oncall issue.Test coverage
poetry run pytest unit_tests/test_airbyte_protocol_serializers.py -q— 4 passed (fail without fix)poetry run pytest unit_tests/destinations -q— 74 passedpoetry run ruff check .,poetry run ruff format --check .,poetry run mypy --config-file mypy.ini airbyte_cdk— cleanLink to Devin session: https://app.devin.ai/sessions/155df3ea04fd462faac82204f95c62d9