Repository navigation
Python: [Bug]: Default registered Pydantic state cannot restore a Message field #9246
Description
Activity
- addedpythonUsage: [Issues, PRs], Target: PythonUsage: [Issues, PRs], Target: PythontriageUsage: [Issues], Target: All issues that still need to be triagedUsage: [Issues], Target: All issues that still need to be triaged
on Oct 10, 2026 - addedreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflowUsage: [Issues], Target: all issues that can be reproduced by the triage workflow
on Oct 10, 2026 github-actions commented
on Oct 10, 2026 on Oct 10, 2026 – with GitHub ActionsContributorMore actions🤖 Automated triage reproduction notes (agent-authored — trust but verify)
Agent analysis
The failure occurs in python/packages/core/agent_framework/_sessions.py::_deserialize_value at line 432, which invokes the registered Pydantic parent decoder before restoring its tagged Message child; _default_state_decoder at line 274 then passes that dictionary to model_validate. It is triggered by an explicitly registered Pydantic model with arbitrary_types_allowed=True and a Message field. Minimal repro: persist that model in AgentSession.state with FileSessionStore and read it using a fresh JSON or MessagePack store.
- Failing test:
python/packages/core/tests/core/test_sessions.py::TestFileSessionStore::test_registered_pydantic_state_with_message_round_trips - Files examined: python/packages/core/agent_framework/_sessions.py, python/packages/core/tests/core/test_sessions.py, python/packages/core/pyproject.toml
- Tests run: test_registered_pydantic_state_with_message_round_trips, test_explicit_pydantic_registration_round_trips, test_registered_child_tag_does_not_hijack_message_payload
- Reported version:
1.21.0 - Current version:
1.21.0
- Failing test:
- addedagentsUsage: [Issues, PRs], Target: Single agentUsage: [Issues, PRs], Target: Single agentand removedtriageUsage: [Issues], Target: All issues that still need to be triagedUsage: [Issues], Target: All issues that still need to be triaged
on Oct 10, 2026 Verified the mechanism on current main (fd52de7). The default codecs are asymmetric:
- Encode:
model_dump()leaves a nestedMessageas an instance in the payload, and_serialize_valuerecurses into it, so it lands on disk as a tagged dict (type: ...). - Decode: the default Pydantic decoder calls
cls.model_validate(...)on the raw payload, so the nested field receives the tagged dict where the field expects aMessageinstance. Nothing in between deep-restores it.
So the stored snapshot is fine; the restore side is missing the mirror of the encoder's recursion. My proposal: make the default Pydantic decoder deep-restore payload items through
_deserialize_valuebeforemodel_validate, leaving custom codecs' contract (raw tagged payloads) untouched. Unregistered models keep the existing implicit-registration path, and unknown type tags still pass through as raw dicts.Opening a draft PR with that change plus round-trip regressions on both
AgentSession.from_dictand a freshFileSessionStore. Happy to adjust if you want the deep-restore somewhere else in the codec chain.- Encode:
Metadata
Metadata
Labels
Type
Projects
- StatusShow more project fieldsNo status
Observed Behavior
A Pydantic application-state model with
arbitrary_types_allowed=Trueand aMessagefield can be explicitly registered withregister_state_typeusing the supplied default codecs.FileSessionStore.setsuccessfully persists this state, but a freshly constructed store cannot restore it. The behavior occurs with both JSON and MessagePack and with the same source, model definition, and explicit registration. The deepest error is a Pydantic validation error because theMessagefield receives a tagged dictionary instead of aMessageinstance.The same registered model also fails in
AgentSession.from_dict(session.to_dict()). In-memorySessionStoreworks. AMessagedirectly inside a normal state mapping, an ordinary scalar Pydantic model, and a nested Pydantic-model field all round-trip. Explicit paired codecs on the application model, reconstructing the child withMessage.from_dict, also work.The persisted snapshot is unchanged after the failed read. This is a state-decoder failure, not syntactically corrupt storage, and the existing non-destructive recovery behavior is correct.
Expected Behavior
Please clarify the intended default-codec contract for a registered Pydantic model containing a separately registered framework/application type. If this combination is supported, a successfully persisted snapshot should restore the typed parent and child with the same module-level registrations. If an explicit parent codec is required, the unsupported default-codec combination should be documented or rejected before creating an unreadable snapshot.
Steps to Reproduce
Messageis already a registered framework state type.AgentSessioncontaining an instance of this model and persist it withFileSessionStore.set.FileSessionStoreand callgetusing the same key. Saving succeeds; restoring fails for both formats.Minimal Reproduction
Error Messages and Stack Traces
The outer store error is
ValueError: Failed to restore session state from '.../key.json'(or.msgpack). Its cause isFailed to deserialize registered state type 'example.application_state' at state.application. The deepest error reports thatlast_messagemust be an instance ofMessage, withinput_type=dict.Package Versions
Tested executable core source: official main
fd52de71579162a888fb2dd7510c57c6014dcdfc, corepyproject.tomlversion1.21.0. The cached editable environment still reportsagent-framework-core==1.19.0metadata; all 109 tracked core source/metadata files were checked against current official Git blobs.pydantic==2.13.5,msgspec==0.21.1. This is source-scoped validation with cached dependencies, not a fresh dependency installation or release-wheel claim.Python Version
Python 3.14.3.
Operating System
Windows.
Regression
Unknown; no earlier version comparison was run.
Additional Context
The public same-process matrix has 24 overlapping observations: 18 normal and 6 restore failures. Separate writer and reader processes confirm JSON and MessagePack persistence with module-level registrations: 8 normal reader observations and 2 failures. These matrices overlap and are not added. There is no hosted service, model, deployment or non-Windows validation.
Source inspection shows the registered encoder recursively translates the
Messagefield into its tagged mapping, while the default Pydantic decoder callsmodel_validatebefore that field is reconstructed. ADR-0034 requires dynamic nested state restoration and preserves existing tagged representations. Any resolution must also preserve the current testtest_registered_child_tag_does_not_hijack_message_payload: globally decoding every child tag before invoking all registered codecs would interfere with existingMessagecontent payloads. Unknown type IDs and explicit raw-payload callback contracts must remain compatible. An explicit parent codec is already a working workaround.The bounded ownership search and complete selected records cover the session/codec implementation in merged #7306, the closed additional-test proposal #7457, and vNext design #8522. #8522 concerns a future workflow architecture and does not authorize a current decoder overhaul. No open fix for this particular default-Pydantic parent/registered-child combination was found in the bounded search; this is not a claim of repository-wide exhaustive ownership coverage.
Acknowledgements
AI Assistance
AI-assisted: Codex; analysis, reproduction, and writing.