[BUG] Edit tool progressively fails on WSL2 9p mounts (statx ENOENT on existing files)
Bug description
The Edit tool fails with ENOENT: no such file or directory, statx on files that verifiably exist when the workspace is on a 9p/drvfs mount (WSL2 mounting a Windows drive). The failure is progressive within a session:
- Early in a session, Edit works on recently-Read files
- After several successful edits, Edit begins failing on files that Read can still access
- Once failures start, they spread — eventually Edit fails on every file, including files it previously edited successfully
- The Read tool continues to work on all affected files throughout
This is the same underlying issue as #28015 (closed for inactivity, not resolution). That report documented ghost file creation; this report adds the progressive session degradation pattern, which was not captured previously and may explain why static reproduction attempts appeared intermittent.
Root cause
The failure chain has three links:
- libuv uses
statx()for all stat operations on Linux (kernels >= 4.11). When Claude Code's Edit tool validates a file before writing, it ultimately callsstatx()via Node.js'sfsmodule.
- The 9p filesystem driver creates stale negative dentries in the VFS dcache. When
statx()does a path lookup on 9p, the kernel's directory entry cache can record "this name does not exist" (a negative dentry) even for files that exist on the server side (Windows/NTFS). This is a known 9p client caching bug (microsoft/WSL#13105, WSL#8443).
- libuv's fallback doesn't trigger. libuv falls back from
statx()tofstatat()only onENOSYS(syscall not implemented). Since 9p returnsENOENT(file not found) — a legitimate-looking errno from a corrupted cache — libuv trusts it and reports the file as missing. No fallback fires.
The progressive degradation occurs because each failed statx() lookup returns the cached negative dentry without revalidating against the server, and new lookups on not-yet-cached paths can race with server-side state to create additional stale entries.
Minimal reproduction sequence
Session on WSL2 with workspace on 9p/drvfs mount:
1. Read file A → succeeds
2. Edit file A → succeeds
3. Read file B → succeeds
4. Edit file B → succeeds
5. (repeat for several files over 10-20 minutes of work)
6. Read file C → succeeds
7. Edit file C → ENOENT: no such file or directory, statx
8. Read file C → still succeeds
9. Edit file A → ENOENT (file A worked earlier)
10. All subsequent Edits → ENOENT regardless of prior Read state
The progression timing varies but the pattern is consistent: Edit degrades monotonically within a session and does not recover.
Suggested fix
We believe this is a negative dentry caching issue in the 9p VFS client. Path-based stat calls hit stale cache; fd-based alternatives (open the file, then validate via the file descriptor) may bypass it. Detecting 9p/drvfs mounts at startup via statfs() and applying a compatible codepath on those mounts would match what other cross-platform tools do (e.g., git's fsmonitor disables features on network filesystems the same way).
Happy to provide more technical detail on the dcache mechanism if useful.
Workaround
Users can route edits through sed -i (Bash tool) or the Write tool, but this defeats the purpose of Edit's diff-based interface. We maintain a per-session decision tree and circuit breaker in project configuration rules (.claude/rules/environment-constraints.md) to route around Edit entirely once failures begin — infrastructure built to avoid a broken core tool.
Environment
- Claude Code: v2.1.132
- OS: Ubuntu 24.04.4 LTS on WSL2
- Kernel: 6.6.87.2-microsoft-standard-WSL2
- Node.js: v22.22.2
- Mount:
D:\on/workspacetype 9p (rw,noatime,cache=5,access=client,msize=65536,trans=fd) - Model: Claude Opus 4.6
Related
- #28015 — Same root cause (statx + 9p dcache), documented ghost file creation, closed for inactivity
- #52771 — Related WSL2/9p performance issue (startup stat blocking)
- microsoft/WSL#13105 — Upstream kernel bug: 9p path operations return ENOENT on existing files
- microsoft/WSL#8443 — Original report of 9p ENOENT coherence failures
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗