Repository navigation
Description
Description
When a workflow uses GroupChatBuilder with checkpoint persistence, checkpoint restore can fail because built-in group-chat envelope types are not included in the default checkpoint deserialization allowlist.
The affected types include:
agent_framework_orchestrations._base_group_chat_orchestrator:GroupChatRequestMessageagent_framework_orchestrations._base_group_chat_orchestrator:GroupChatParticipantMessageagent_framework_orchestrations._base_group_chat_orchestrator:GroupChatResponseMessage
These are framework-owned types emitted and routed by the group-chat orchestration implementation, but users currently need to manually add them to FileCheckpointStorage(allowed_checkpoint_types=...).
Error
Failed to decode pickled checkpoint data: Checkpoint deserialization blocked for type 'agent_framework_orchestrations._base_group_chat_orchestrator:GroupChatParticipantMessage'. To allow this type, either include its 'module:qualname' key in the 'allowed_types' set passed to 'decode_checkpoint_value', or add it to 'allowed_checkpoint_types' on your checkpoint storage.
Reproduction
from agent_framework._workflows._checkpoint import FileCheckpointStorage
from agent_framework_orchestrations import GroupChatBuilder
storage = FileCheckpointStorage("./checkpoints")
workflow = GroupChatBuilder(
participants=[...],
orchestrator_agent=...,
checkpoint_storage=storage,
).build()
# Run until a checkpoint contains a group-chat envelope, then restore it.Expected behavior
Framework-owned orchestration message types should be included in the framework's trusted checkpoint type registry by default, or the orchestration package should provide a documented helper that registers all of its checkpoint-safe types.
Users should not need to maintain an internal module-path allowlist for built-in MAF orchestration envelopes.
Workaround
storage = FileCheckpointStorage(
"./checkpoints",
allowed_checkpoint_types=[
"agent_framework_orchestrations._base_group_chat_orchestrator:GroupChatRequestMessage",
"agent_framework_orchestrations._base_group_chat_orchestrator:GroupChatParticipantMessage",
"agent_framework_orchestrations._base_group_chat_orchestrator:GroupChatResponseMessage",
],
)Additional context
The same consideration may apply to other framework-owned orchestration payloads, such as handoff and Magentic orchestration event/request types. It would be useful to audit all built-in types that can cross a checkpoint boundary and ensure they are registered consistently.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
z2Ace0107 commentedon Aug 20, 2026
I can investigate this issue and prepare a focused regression fix, subject to maintainer guidance on the registration boundary.
From the current main branch, FileCheckpointStorage passes an allowlist to the restricted checkpoint decoder, while the GroupChat envelope types live under the agent_framework_orchestrations.* namespace. The decoder currently auto-allows agent_framework.* types, which appears to explain why these framework-owned messages are rejected during restore.
My initial plan would be:
Before I start, could you confirm whether the orchestration package should register these checkpoint-safe types, or whether you prefer another mechanism? Should Handoff and Magentic checkpoint payloads be handled separately?
I’m happy to take this issue if that direction is acceptable.
atty57 commentedon Aug 20, 2026
Confirmed on
mainand opened a draft PR for this: #7791. Ace (@z2Ace0107) — apologies, I had this branched before your comment landed; happy to close mine if you'd rather take it, and either way the notes below should be useful.The cause is the module-prefix rule in the restricted checkpoint unpickler.
_checkpoint_encoding.pyauto-allows anything under_FRAMEWORK_MODULE_PREFIX = "agent_framework."(with the trailing dot), soagent_framework_orchestrations— a sibling distribution, not a submodule — falls through to the generic "blocked type" branch, which is why these read as user types.Minimal repro without a workflow or storage backend:
On the audit point: alongside the three group chat envelopes, the other orchestration types that cross a checkpoint boundary are the
request_infopayloads and responses —HandoffAgentUserRequest(_handoff.py:439),AgentRequestInfoResponse(_orchestration_request_info.py:101),MagenticPlanReviewRequest/MagenticPlanReviewResponse(_magentic.py:1048) along with the ledger types nested in the request, andMagenticResetSignal(_magentic.py:1271).GroupChatState,OrchestrationState, andMagenticContextare not affected — they persist throughto_dict/from_dictrather than pickle.The PR registers that set via the existing
register_checkpoint_typeAPI at package import, so nothing in core's prefix rule changes and no other package becomes trusted. The alternative — broadening the core prefix to cover the wholeagent_framework_*family — would fix every first-party package at once but also auto-trusts any installed distribution using that module name, so it seemed like a maintainer call rather than something to fold into this fix.github-actions commentedon Aug 21, 2026
🤖 Automated triage reproduction notes (agent-authored — trust but verify)
Agent analysis
Repro: restricted restore fails in
python/packages/core/agent_framework/_workflows/_checkpoint_encoding.py::_RestrictedUnpickler.find_classfor the three envelope classes defined inpython/packages/orchestrations/agent_framework_orchestrations/_base_group_chat_orchestrator.py. Minimal repro: encode each group-chat envelope and calldecode_checkpoint_value(encoded, allowed_types=frozenset()); all three raiseWorkflowCheckpointExceptionbecause theiragent_framework_orchestrations.*types are blocked.python/packages/orchestrations/tests/test_group_chat_checkpoint_restore.py1.1.0manjunathshiva commentedon Sep 10, 2026
Opened #8258 for this. It follows the shape Atharva Vichare (@atty57) used in #7791 — registering the
framework-owned types via the public
register_checkpoint_type— which was closed on 2026-09-04 asa stale draft rather than on approach, and it addresses the Copilot comment left open there.
Ace (@z2Ace0107), you offered on this first on 08-20: if you have work in progress, say so and I will
stand down rather than duplicate it.
Two things the end-to-end repro turned up that refine the issue, regardless of whose fix lands:
(
_base_group_chat_orchestrator.py:434,467) — agent participants get a coreAgentExecutorRequest, already trusted. So you need at least one customExecutorparticipant.That, plus the existing checkpoint tests using
InMemoryCheckpointStorage(whichdeepcopys andnever reaches the unpickler), is why this went unnoticed.
list_checkpointslogs and skips what it cannot decode. A two-round groupchat writes six checkpoints, lists two, and
get_latestreturns a stale one — quiet data loss,not the loud
UnpicklingErrorabove, which only surfaces on a directload(). Same invisibilityOleg Solozobov (@dev404ai) reports in Python: [Bug]: get_latest returns a stale checkpoint when the newest one cannot be decoded #7831.
The PR registers ten types, each verified against a call site, including
MagenticProgressLedger/Itemwhich are nested inMagenticPlanReviewRequest.current_progress.I deliberately did not broaden
_FRAMEWORK_MODULE_PREFIXto the undottedagent_framework:it would fix the whole class in one line, but on a pickle allowlist it auto-trusts any installed
distribution merely named
agent_framework_*, which felt like a maintainer's security call.Sequencing note: once #8214 adds save-time validation this stops being silent and starts failing on
the first checkpoint, so affected users go from degraded to blocked — may be worth landing the
registration first.