Skip to content

Python: [Bug]: FileSessionStore cannot quarantine corrupt snapshots near Windows MAX_PATH #9885

Open

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

  1. On Windows with LongPathsEnabled=0, create a FileSessionStore whose 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.
  2. Write malformed bytes to the snapshot path.
  3. Call await store.get(session_id).
  4. 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.

Activity

  1. added
    pythonUsage: [Issues, PRs], Target: Python
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Oct 30, 2026
  2. Aaravkhanal commented on Oct 30, 2026

    @Aaravkhanal
    Author

    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.

  3. added
    reproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow
    on Oct 30, 2026
  4. github-actions commented on Oct 30, 2026

    @github-actions
    Contributor

    🤖 Automated triage reproduction notes (agent-authored — trust but verify)

    Agent analysis

    The bug occurs in python/packages/core/agent_framework/_sessions.py::_quarantine_corrupt_snapshot at line 2195 when a near-limit snapshot path is expanded with the full filename, UUID, and .corrupt suffix. Minimal repro: create a 254-character corrupt snapshot path, make os.replace reject destinations of 260 or more characters, and call FileSessionStore.get(); the attempted destination is 296 characters and the source remains.

    • Failing test: python/packages/core/tests/core/test_sessions.py::TestFileSessionStore::test_corrupt_session_file_near_legacy_windows_max_path_is_quarantined
    • Files examined: python/packages/core/agent_framework/_sessions.py, python/packages/core/tests/core/test_sessions.py, python/packages/core/pyproject.toml
    • Tests run: python/packages/core/tests/core/test_sessions.py::TestFileSessionStore::test_corrupt_session_file_near_legacy_windows_max_path_is_quarantined, python/packages/core/tests/core/test_sessions.py::TestFileSessionStore::test_corupt_session_file_is_quarantined_and_retry_returns_none
    • Current version: 1.24.0
  5. added
    agentsUsage: [Issues, PRs], Target: Single agent
    and removed
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Oct 30, 2026
  6. eavanvalkenburg commented on Nov 2, 2026

    @eavanvalkenburg
    Member

    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.

  7. Aaravkhanal commented on Nov 6, 2026

    @Aaravkhanal
    Author

    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-latest result, or do you specifically need a run from a separate Windows machine? I’ll wait for your direction before opening any PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

agentsUsage: [Issues, PRs], Target: Single agentpythonUsage: [Issues, PRs], Target: PythonreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions