Repository navigation
Description
Checks
- I have updated to the lastest minor and patch version of Strands
- I have checked the documentation and this is not expected behavior
- I have searched existing issues and there are no duplicates of my issue
SDK Language
Python
Strands Version
main at 08f5bdd3ad105af661f76c98b9adb0af024ae7f7
Language Runtime Version
Any supported Python version; this is an implementation-level asynchronous write race
Operating System
Any; not operating-system-specific
Installation Method
git clone
Steps to Reproduce
- Create a Python
Graphwith two parallel entry nodes and attachSnapshotSessionManagerusing the defaultmulti_agent_save_latest_on="node"strategy. - Use a deterministic asynchronous
Storagebackend forsnapshot_latest.jsonthat:- blocks node A's first write after capturing state
S_A; - lets node B complete and persist newer state
S_AB; - releases A so its older write finishes last; and
- blocks the invocation-end write before it commits.
- blocks node A's first write after capturing state
- Read or restore
snapshot_latest.jsonwhile the invocation-end write is blocked. - Observe that the stored snapshot is
S_A, so B is no longer marked complete and may execute again after restart.
This ordering can occur naturally with remote storage when parallel node saves have different latency and the process stops before the invocation-end save repairs the checkpoint.
Expected Behavior
Once a snapshot includes a completed node, a later-finishing save must not replace it with an older execution frontier. After B completes, snapshot_latest.json must retain state at least as new as S_AB.
Actual Behavior
Python node-save callbacks can overlap, and every save unconditionally overwrites the same key. Storage completion order can therefore differ from snapshot capture order: A's older S_A write can replace B's newer S_AB write. Restoring during that failure window loses B's completed state and can repeat non-idempotent work.
Additional Context
The race is present in the current Python code path:
Graph._execute_nodes_parallelruns node streams in separateasynciotasks.- Each task updates shared Graph state and independently awaits
AfterNodeCallEventcallbacks inGraph._execute_node. SnapshotSessionManager._save_multi_agent_latestcaptures state and asynchronously overwrites one shared key without per-orchestrator serialization or a monotonic write condition.
LocalFileStorage is unlikely to expose the race because its replacement path does not yield mid-write. An asynchronous backend such as S3 can expose it.
This specific race does not occur in the TypeScript Graph path, either at the 100429263 revision originally cited by this issue or on current main. Parallel node producers use await queue.send(...) for AfterNodeCallEvent; one queue consumer awaits the hook callback and calls ack() before processing the next queued event. Its Graph-driven snapshot saves therefore cannot overlap. TypeScript Swarm also executes nodes sequentially.
The TypeScript SessionManager.saveSnapshot method itself has no lock or monotonic-write guard, so independently issuing concurrent manual saves to the same location could still race. That lower-level possibility is not the automatic parallel-Graph execution path described by this issue. The original PR discussion concluded that both SDKs were affected after comparing the save methods, but tracing event dispatch shows that conclusion was incorrect.
Possible Solution
Serialize the complete capture + write operation per (session_id, orchestrator_id), using the same mechanism for node-end and invocation-end saves. Locking only after capture would still permit stale snapshots to queue.
Add the deterministic delayed-write regression described above and assert that the final readable snapshot contains both completed nodes. This fix is Python-specific; no TypeScript port is needed unless its event-dispatch model changes.
Related Issues
Metadata
Metadata
Assignees
Labels
Type
Fields
Language
Activity
[-][BUG] Parallel node saves can regress the latest multi-agent snapshot[/-][+][BUG] Python parallel node saves can regress the latest multi-agent snapshot[/+]mayankdas2005 commentedon Sep 23, 2026
Hi @nicolas-m-romero , is this issue open to work on? Can i take this up if anyone isnt assigned to it? Thanks
nicolas-m-romero commentedon Sep 24, 2026
@mayankdas2005 this issue is not open to work on, however, if you are looking for opportunities to contribute to the repository be on the lookout for issues tagged with "ready for contribution" tag.
mayankdas2005 commentedon Sep 24, 2026
Thanks for the clarification @nicolas-m-romero. I'll keep this in mind.