Skip to content

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

Open
he-yufeng wants to merge 1 commit into
microsoft:mainfrom
he-yufeng:fix/serialization-fromdict-type-mismatch
Open

Python: make SerializationMixin.from_dict enforce the documented type check#7256
he-yufeng wants to merge 1 commit into
microsoft:mainfrom
he-yufeng:fix/serialization-fromdict-type-mismatch

Conversation

@he-yufeng

@he-yufeng he-yufeng commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Fixes #7255.

Problem

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.

Fix

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()

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.

Tests

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
@he-yufeng
he-yufeng temporarily deployed to github-app-auth July 22, 2026 11:01 — with GitHub Actions Inactive
@he-yufeng
he-yufeng temporarily deployed to github-app-auth July 22, 2026 11:01 — with GitHub Actions Inactive
@he-yufeng
he-yufeng temporarily deployed to github-app-auth July 22, 2026 11:01 — with GitHub Actions Inactive
@agent-framework-automation agent-framework-automation Bot added the python Usage: [Issues, PRs], Target: Python label Jul 22, 2026
@he-yufeng
he-yufeng temporarily deployed to github-app-auth July 22, 2026 11:02 — with GitHub Actions Inactive

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 on lines 543 to 544
if (supplied_type := value.get("type")) and supplied_type != type_id:
raise ValueError(f"Type mismatch: expected '{type_id}', got '{supplied_type}'")
@github-actions

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
TOTAL45115509388% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
9217 33 💤 0 ❌ 0 🔥 2m 32s ⏱️

@he-yufeng
he-yufeng temporarily deployed to github-app-auth July 22, 2026 14:19 — with GitHub Actions Inactive
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

3 participants