Relationships
#2463 Windows: concurrent data save can fail with Access is denied renaming the latest marker
Opened by stack72 · 9/24/2026
Problem
concurrent save returns unique versions with distinct content
(src/infrastructure/persistence/unified_data_repository_test.ts:196) failed
intermittently on the Windows Compatibility workflow for 2ebf013c
(run 35931978224):
PermissionDenied: Access is denied. (os error 5): rename '...\concurrent-save\.<uuid>.tmp' -> '...\concurrent-save\latest'
at atomicWriteTextFile (src/infrastructure/persistence/atomic_write.ts:42:5)
at FileSystemUnifiedDataRepository.updateLatestMarker (src/infrastructure/persistence/unified_data_repository.ts:2048)
at FileSystemUnifiedDataRepository.save (src/infrastructure/persistence/unified_data_repository.ts:666:5)
at Promise.all (index 7)13080 other tests passed. The same test passed on earlier green Windows runs (65204770, 901daee6), and none of the persistence files involved have changed recently, so this is an intermittent race rather than a new breakage.
Likely cause
The test runs 10 save() calls on the same data name at once. Each one ends in
updateLatestMarker, which removes latest and then calls
atomicWriteTextFile, which writes a temp file and renames it onto latest.
On POSIX, concurrent renames onto the same target are atomic. On Windows,
renaming onto a file that another rename or remove is touching at the same
moment can fail with ERROR_ACCESS_DENIED (os error 5). The failure comes from
the rename in atomic_write.ts:42.
This is probably not test-only: any concurrent saves of the same data name in one process on Windows (parallel workflow steps writing the same resource, for example) could hit the same error and fail a save that should succeed.
Possible directions
- Serialize
updateLatestMarkerper data-name directory within the repository. - Retry the rename in
atomicWriteTextFileon Windows PermissionDenied with a short bounded backoff, as other Windows-safe atomic-write implementations do. - Drop the remove-before-write in
updateLatestMarker: the rename already replaces the target, and the extra remove widens the race window.
Open
No activity in this phase yet.
Sign in to post a ripple.