Repository navigation
Description
Observed Behavior
On Windows with legacy MAX_PATH handling enabled (long paths disabled), FileSessionStore.get() can fail to quarantine a corrupt snapshot even when the snapshot file's own path fits under 260 characters.
_quarantine_corrupt_snapshot() names the quarantine destination .<full snapshot filename>.<uuid>.corrupt. For a 128-character session ID and a sufficiently deep storage directory, that destination exceeds the path limit. os.replace() then raises OSError; get() wraps it as ValueError: ... the corrupt snapshot could not be quarantined. The corrupt file remains in place, so every retry encounters the same failure.
Expected Behavior
Quarantine the corrupt snapshot using a bounded, session-ID-independent sibling filename, then raise the existing error that says the corrupt snapshot was quarantined and a retry can create a fresh session.
Steps to Reproduce
- On Windows with
LongPathsEnabled=0, create aFileSessionStorewhose storage directory is deep enough that the snapshot path for a 128-character session ID is below 260 characters but the quarantine destination is above 260. - Write malformed bytes to the snapshot path.
- Call
await store.get(session_id). - Observe that it raises the “corrupt snapshot could not be quarantined” error and leaves the original corrupt file in place; repeated calls fail the same way.
Minimal Reproduction
import asyncio
import tempfile
from pathlib import Path
from agent_framework import FileSessionStore
async def main():
base = Path(tempfile.mkdtemp())
session_id = "x" * FileSessionStore.MAX_SESSION_ID_LENGTH
snapshot_name_length = len(session_id) + len(".json")
# Place the snapshot near the legacy Windows MAX_PATH limit.
padding = 245 - len(str(base)) - 2 - snapshot_name_length
assert padding > 0
storage = base / ("d" * padding)
store = FileSessionStore(storage)
snapshot = store._session_file_path(session_id)
assert len(str(snapshot)) < 260
snapshot.write_bytes(b"not-json")
try:
await store.get(session_id)
except ValueError as exc:
print(exc)
print("corrupt snapshot remains:", snapshot.exists())
asyncio.run(main())On the affected Windows configuration, the current quarantine destination is roughly 40 characters longer than the snapshot path, causing the rename to exceed the limit.
Package Versions
Unreleased source checkout at 59b183b5bcb2f192c6206d50c2e19cfed396dada (agent-framework-core); Python 3.12.16.
Operating System
Windows (legacy MAX_PATH behavior; long paths disabled).
Regression
Unknown.
Additional Context
I reproduced the path-length failure against this source checkout on macOS by applying a simulated 260-character guard to the quarantine rename: a 254-character snapshot path produced a 296-character quarantine path, get() raised the wrapped error, and the corrupt file remained. I have not run the reproduction on native Windows.
This is related to #9682, but covers the read-time corrupt-snapshot recovery path. PR #9739 shortens the write-time temporary filename and does not change _quarantine_corrupt_snapshot().
AI assistance helped inspect the code, construct and run the simulated reproduction, and draft this report. The native Windows behavior still needs confirmation.
Acknowledgements
- I searched existing issues and did not find a duplicate.
- I verified the reproduction details described above; the Windows path-limit behavior was simulated locally, not run on native Windows.
- I will wait for explicit maintainer agreement before starting implementation of this non-trivial change.
Metadata
Metadata
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
Aaravkhanal commentedon Oct 30, 2026
I would like to implement this focused recovery-path fix. The local reproduction confirms the quarantine destination grows beyond the legacy path limit; I have not run it on native Windows. Could a maintainer confirm this scope and mark the issue ready-for-implementation if it is approved? I will keep the change limited to a bounded quarantine filename and a regression test, coordinated with #9682 / PR #9739.
github-actions commentedon Oct 30, 2026
🤖 Automated triage reproduction notes (agent-authored — trust but verify)
Agent analysis
The bug occurs in
python/packages/core/agent_framework/_sessions.py::_quarantine_corrupt_snapshotat line 2195 when a near-limit snapshot path is expanded with the full filename, UUID, and.corruptsuffix. Minimal repro: create a 254-character corrupt snapshot path, makeos.replacereject destinations of 260 or more characters, and callFileSessionStore.get(); the attempted destination is 296 characters and the source remains.python/packages/core/tests/core/test_sessions.py::TestFileSessionStore::test_corrupt_session_file_near_legacy_windows_max_path_is_quarantined1.24.0eavanvalkenburg commentedon Nov 2, 2026
Could someone with native Windows access run this reproduction on current main with long paths disabled and share the Windows/Python build, the actual rename error, and the snapshot and attempted quarantine path lengths? The report and automated reproduction currently simulate MAX_PATH on another platform. A native result would establish the affected supported configuration before we mark this implementation-ready; no core API change is being requested.
Aaravkhanal commentedon Nov 6, 2026
I’m on macOS, so I can’t run this natively here. I checked the repository workflow: its Windows test job runs on pull requests, not as a standalone dispatch. Would a narrowly scoped reproduction-only PR be acceptable to get a native
windows-latestresult, or do you specifically need a run from a separate Windows machine? I’ll wait for your direction before opening any PR.