Skip to content

Python: make SerializationMixin.from_dict enforce the documented type check - #7256

Merged
Eduard van Valkenburg (eavanvalkenburg) merged 2 commits into
microsoft:mainfrom
he-yufeng:fix/serialization-fromdict-type-mismatch
Jul 30, 2026
Merged

Python: make SerializationMixin.from_dict enforce the documented type check#7256
Eduard van Valkenburg (eavanvalkenburg) merged 2 commits into
microsoft:mainfrom
he-yufeng:fix/serialization-fromdict-type-mismatch

Conversation

@he-yufeng

@he-yufeng Yufeng He (he-yufeng) commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Motivation & Context

SerializationMixin.from_dict documents that a mismatched type field raises ValueError, but the guard could never fire: it resolved the expected identifier via cls._get_type_identifier(value), and that helper *prefers the payload's own type field when one is present. Any supplied type therefore "matched" itself, and a payload like {"type": "function_tool", "role": "user", "contents": []} silently deserialized into a Message, with the wrong type baked in until the next to_dict() rewrote it.

Description & Review Guide

  • What are the major changes?
    Resolve the expected identifier from the class (no payload), which is also what to_dict() writes, so the mismatch guard now works as documented: type_id = cls._get_type_identifier().
  • What is the impact of these changes?
    In every previously valid case the class-resolved identifier is the same string the payload carried, so well-formed payloads (including no-type payloads and dependencies= injection, which keys on the same id) are unchanged. Classes that do polymorphic deserialization (Content, the file-access harness entries) override from_dict themselves and are unaffected.
  • What do you want reviewers to focus on?
    The two behavioral edges: payloads that omit type entirely, and the polymorphic subclasses that override from_dict.

Related Issue

Fixes #7255

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR title and description follow the guidelines
  • Documentation has been updated if needed (not needed: docstring already documents the raised ValueError)

Two new tests in test_serializable_mixin.py: mismatched type raises on both from_dict and from_json. Full file passes (28/28). pytest packages/core/tests/core is green except test_feature_stage.py::test_feature_id_allows_lowercase_values, which fails identically on a clean main checkout (pre-existing, unrelated). The exact repro from the issue now raises Type mismatch: expected 'message', got 'function_tool'.

… check

from_dict resolved the expected type identifier from the payload itself
(_get_type_identifier(value) prefers value["type"]), so the mismatch
guard could never fire: any supplied 'type' matched itself, and a payload
like {"type": "function_tool", ...} silently deserialized into a Message,
getting its type rewritten on the next to_dict. The docstring has always
promised a ValueError on mismatch.

Resolve the identifier from the class instead, matching what to_dict
emits, so a mismatched or foreign 'type' now raises as documented.
Payloads without a 'type' field and dependency-injection lookups are
unchanged: in every previously valid case the class-resolved identifier
is the same string the payload carried.

Fixes microsoft#7255

Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 22, 2026 11:01
@agent-framework-automation agent-framework-automation Bot added the python Usage: [Issues, PRs], Target: Python label Jul 22, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a correctness issue in the Python core serialization layer where SerializationMixin.from_dict() could not actually enforce its documented “type mismatch raises ValueError” behavior, allowing payloads with an incorrect "type" discriminator to deserialize into the wrong class (Fixes #7255).

Changes:

  • Make SerializationMixin.from_dict() derive the expected type identifier from the target class rather than the incoming payload, so the mismatch guard can trigger.
  • Add regression tests ensuring mismatched "type" is rejected for both from_dict() and from_json().

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
python/packages/core/agent_framework/_serialization.py Fixes the mismatch check by resolving the expected type identifier from the class instead of the payload.
python/packages/core/tests/core/test_serializable_mixin.py Adds tests verifying mismatched "type" raises for both dict and JSON inputs.

Comment thread python/packages/core/agent_framework/_serialization.py
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/core/agent_framework
   _serialization.py1731293%355–356, 561, 571, 636, 639, 679–680, 684–685, 687, 689
TOTAL46102447990% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
9547 34 💤 0 ❌ 0 🔥 2m 29s ⏱️

@eavanvalkenburg

Copy link
Copy Markdown
Member

please make sure to use the defined PR template Yufeng He (@he-yufeng)

@he-yufeng

Copy link
Copy Markdown
Contributor Author

Done, body rewritten to the defined template (Motivation & Context / Description & Review Guide / Related Issue / Contribution Checklist), with the test evidence folded into the checklist section.

Merged via the queue into microsoft:main with commit 93e8cb2 Jul 30, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: SerializationMixin.from_dict silently accepts mismatched type identifiers

4 participants