Windows: Write/Edit tools fail with spurious EEXIST on sandboxed workspace (bindflt/bfs mount) — temp file does not exist
Environment: Claude Code on Windows 11 Pro (10.0.26200). Workspace is a sandboxed mount at %LOCALAPPDATA%\.cache\work (cowork-style; ACLs show a CodexSandboxUsers group).
Symptom: Every Write and Edit tool call fails with:
EEXIST: file already exists, open '<target>.tmp.<pid>.<random-hex>'
Deterministic — 8/8 attempts in one session, across multiple directories.
Evidence the EEXIST is spurious:
- The temp filename has a fresh random suffix each attempt; a real collision is impossible.
- No
*.tmp.*files exist anywhere in the affected directories (verified by glob). - Immediately after each failure, a plain write to the SAME path from a child process succeeds.
Runtime split (all tested in the same session, same directory):
| Route | Result |
|---|---|
| Node (harness Write/Edit, exclusive-create temp) | EEXIST (spurious) |
| git-bash (MSYS) mkdir | false "File exists" on nonexistent names |
| PowerShell New-Item -ItemType Directory | silent phantom: reports success, creates nothing |
| Python io.open("w"), os.open(O_CREAT\|O_EXCL), os.mkdir | all succeed |
| cmd.exe mkdir, bash cat >, PowerShell Set-Content / [IO.File]::WriteAllText | all succeed |
Note Python's O_EXCL succeeds — the filesystem's exclusive-create is fine; only the Node/libuv and MSYS code paths get intercepted.
Filter stack (fltmc filters, admin): only stock Microsoft drivers active — bindflt (1 instance), bfs (7), WdFilter, CldFlt, luafv; wcifs/UnionFS idle. The sandbox pair bindflt (path mapping) + bfs (brokered file ops) is the apparent interceptor.
Ruled out: added a temporary Windows Defender path exclusion for the workspace and retested — EEXIST persisted unchanged, ruling out WdFilter/AV entirely. No third-party AV or sync client involved; this narrows the cause to the sandbox virtualization layer itself.
Impact: every native file edit fails on such workspaces; users must fall back to shell/Python writes, losing atomic saves and post-write hook integration.
Suggested fix: when the atomic-save temp file's exclusive-create returns EEXIST, (a) retry once with a new random name, and if that also fails, (b) fall back to a direct non-exclusive write (CREATE_ALWAYS semantics) — optionally gated to detected sandbox/bindflt mounts.