[BUG] Cowork stale-cache corruption reproduced under Claude Fable 5 — host writes are clean on disk, the sandbox read view truncates (full diagnosis + fix)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Summary
Cowork's sandbox serves a corrupted view of any file the host modified after the sandbox first cached its attributes. The Windows disk is clean throughout; the harness Write/Edit tools write correctly. The sandbox FUSE chain refreshes data pages but never invalidates cached file size, so grown files read back hard-clipped at the old size and shrunk files read back null-padded to the old size. No invalidation works from inside the sandbox. Real data loss happens when sandbox tooling (cp, zip, sed, git, build scripts) reads the truncated view and writes it back over the clean file on disk.
Reproduced 2026-06-11 on the current desktop build under Claude Fable 5, with independent disk verification via PowerShell 7 outside the app. This confirms #50873 from the write side and matches the mechanism #40264 identified before that issue was closed as invalid. It also shows the bug needs no session boundary and no external editor: the harness's own Write/Edit tools trigger it within a single session.
Environment
- Windows 11 host, packaged desktop app (Claude_pzs8sxrjxfjjc), Cowork mode
- Model: claude-fable-5, session date 2026-06-11
- Selected-folder mount: fuse.bindfs over /mnt/.virtiofs-root; outputs mount: direct virtiofs FUSE
- Both mounts show identical behavior; all results deterministic across two runs (2026-05-23 and 2026-06-11)
Controlled matrix
Base files created inside the sandbox (bash, ground truth on disk), mutated by host-side harness tools, then hashed three ways: sandbox (stat/md5sum), harness Read tool, and PowerShell on the host (Get-FileHash, ReadAllBytes).
| Operation | Expected | Sandbox view | Windows disk (PowerShell) |
|---|---|---|---|
| Write tool, new file (1109 B) | 1109 B | 1109 B, md5 match | clean, md5 match |
| Write tool over 559 B file, new content 1109 B | 1109 B | 559 B: the NEW content clipped at the OLD size | clean 1109 B, correct md5 |
| Write tool over 2209 B file, new content 559 B | 559 B | 2209 B: new content + 1650 null bytes | clean 559 B, zero nulls |
| Edit tool, +162 B growth on 1109 B file | 1271 B | 1109 B: tail clipped | clean 1271 B, correct md5 |
| Edit tool, same-length change | 1109 B | 1109 B, md5 match | clean, md5 match |
| PowerShell Add-Content append (any host process) | 614 B | 559 B: append invisible | append present |
The decisive detail: md5 of the sandbox's 559 B view of the grown file equals md5 of the first 559 bytes of the NEW content. Data pages refresh; st_size does not. The kernel clamps reads at the stale size (pread past it returns 0 bytes) and zero-fills the gap when the file shrank.
Localization
stat --cached=never (forced statx, no STATX_DONT_SYNC) still returns the stale size on the direct virtiofs mount. That forces a GETATTR to the FUSE server, so the stale value is served by the host-side daemon (virtiofsd / WinFsp bridge), not by guest kernel attribute caching. The daemon does not observe host-side file changes and holds the stale size indefinitely; no TTL expiry was observed within a session.
Invalidation attempts from inside the sandbox, all ineffective: touch, os.utime, O_RDWR open/close, statx --cached=never, posix_fadvise(POSIX_FADV_DONTNEED), parent directory re-listing, hardlink creation. rename worked once on one file and failed on two others, so it is not a workaround. drop_caches and fusermount are denied in the sandbox. The only reliable repair is rewriting the correct content through the sandbox, which updates the daemon's cached size as a side effect.
Why this destroys user data
The disk stays clean until sandbox tooling touches the file. Any read-then-write inside the sandbox commits the truncated view to the real disk: in this session's tests, cp of a stale-view file produced a 559 B copy of a clean 1109 B file on disk. zip, sed -i, git add, npm publish and build scripts do the same. Every tool call reports success; the user discovers the loss later, often after backups have rotated. #50873 nearly shipped a truncated package to PyPI through exactly this path.
Suggested fixes
- virtiofsd/bridge: watch mounted directories host-side (ReadDirectoryChangesW) and push FUSE_NOTIFY_INVAL_INODE on change, or stop caching attributes for writable shares (metadata cache=none; the cost on small document mounts is negligible).
- Alternatively route harness Write/Edit through the guest side of the mount so the daemon's cache sees its own writes; the tools already map every host path to a VM path.
- Cheap interim guard: after any harness Write/Edit, compare host-side size with sandbox
statsize and surface a warning on divergence. The failure is currently invisible at every layer that reports status. - Triage note: #40264 documented this mechanism in March 2026 and was closed as invalid; the analysis there was correct. Related: #38993, #42520, #41710, #45433, #55877.
What Should Happen?
A sandbox read of a mounted file should reflect the file's current state on the host disk, or fail loudly. After a host-side Write/Edit (or any host process modifying the file), stat, open/read, and every downstream tool inside the sandbox should see the new size and content. Silent service of a hybrid view (new data clipped or zero-padded to a stale size) is the worst available behavior: it passes every success check while poisoning any pipeline that reads the file.
Error Messages/Logs
---shell
No error messages at any layer. All Write/Edit tool calls report success. Sandbox reads silently return truncated/padded data.
Sandbox evidence (grow case, file wB.txt; expected 1109 B, md5 cfaefacb31289dd89a1f9ee4500d91b9):
$ stat -c%s wB.txt
559
$ md5sum wB.txt
089bf18b7cafad30320ebefb3d1a20d4 # = md5 of the FIRST 559 BYTES OF THE NEW CONTENT
$ stat --cached=never -c%s wB.txt
559 # forced GETATTR still stale -> server-side cache
pread(fd, 200, offset=559) -> 0 bytes (read clamped at stale EOF)
Shrink case (wC.txt; expected 559 B):
sandbox: 2209 B, 1650 null bytes after the new content
$ tr -cd '\000' < wC.txt | wc -c
1650
Host PowerShell, same instant, both files:
wB.txt len=1109 md5=cfaefacb31289dd89a1f9ee4500d91b9 nulls=0 # clean
wC.txt len=559 md5=bc2302c31a328bd04b5df16cd3da9940 nulls=0 # clean
Laundering vector (sandbox):
$ cp wB.txt wB_copy.txt && stat -c%s wB_copy.txt
559 # truncated copy now exists on the real disk
echo 3 > /proc/sys/vm/drop_caches -> Permission denied (no in-sandbox invalidation possible)
---
Steps to Reproduce
<session> and <folder> are placeholders for the live mount path.
- On Windows, start a Cowork session with any folder selected (mounted in the sandbox under
/sessions/<session>/mnt/<folder>/). - In the sandbox (bash), create a base file so the FUSE chain caches its attributes:
printf 'A%.0s' {1..500} > /sessions/<session>/mnt/<folder>/probe.txt - Have the harness Write tool overwrite
probe.txtwith approx 1000 bytes of different content. The tool reports success. - In the sandbox:
stat -c%s probe.txtreturns 500 (stale; host disk is 1000), andmd5sum probe.txtreturns the hash of the FIRST 500 BYTES of the new content. - On the host in PowerShell:
(Get-Item probe.txt).Lengthreturns 1000, andGet-FileHash probe.txt -Algorithm MD5returns the correct hash of the full new content. - Demonstrate disk corruption from the clean state — in the sandbox:
cp probe.txt probe2.txt. The copyprobe2.txtis 500 bytes on the host disk. Data loss, zero errors emitted.
Variations, reproduced on both a bindfs-over-virtiofs mount and a direct virtiofs mount: the Edit tool growing a file clips the growth from the tail of the sandbox view; the Write tool shrinking a file null-pads the view to the old size; a PowerShell Add-Content append from the host is invisible in the sandbox; a Write to a path that never previously existed is clean; same-length edits are clean. The defect requires only that the sandbox cached the file's attributes before the host-side change; no session boundary is needed.
Variations, all reproduced on both a bindfs-over-virtiofs mount and a direct virtiofs mount: Edit tool growing a file clips the growth from the tail of the sandbox view; Write tool shrinking a file null-pads the sandbox view to the old size; a PowerShell Add-Content append from the host is invisible in the sandbox; Write to a path that did not previously exist is clean; same-length edits are clean. The defect requires only that the sandbox cached the file's attributes before the host-side change; no session boundary is needed.
Claude Model
Other
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
N/A — Cowork (Claude Desktop packaged app, Claude_pzs8sxrjxfjjc), not the CLI. Repro is against the bundled Cowork agent runtime.
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Other
Additional Information
Workarounds in production use across seven document projects (validated over three weeks):
- Treat host-tool writes and sandbox reads as separate worlds. After any harness Write/Edit to an existing file, no sandbox read of that file is trustworthy until the correct content has been rewritten through the sandbox (temp file + atomic rename, then SHA-256 verify).
- Never run pack/build/copy/publish operations in the sandbox over files the harness edited, in this or any earlier session, without first cross-checking host-side size vs sandbox stat size.
- Sentinel EOF markers as the last line of every important file make truncation detectable with tail -1.
- Null-byte scan catches the shrink case: tr -cd '\000' < file | wc -c should return 0.
- Write to a brand-new path is safe; prefer write-new + host-side rename over overwrite where possible.
Method note: this report was prepared with Claude (Fable 5) running inside the affected Cowork session; all host-side disk verification (Get-FileHash, ReadAllBytes, Add-Content probes) was performed manually in PowerShell 7 outside the app. An earlier audit (2026-05-23) wrongly concluded the harness Write/Edit tools corrupt the disk, because it verified "disk" state through the sandbox view, i.e. through the cache that lies. Independent host-side hashing is the only verification that means anything here; triage should not trust any in-sandbox evidence of disk state, in this report or in the related ones.
This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗