[BUG] Cowork: virtiofs FUSE mount serves truncated/stale files — host-side file changes not reflected in VM
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?
When a file in a mounted folder is modified on the host (by any process — editor, sync tool, script) after Cowork mounts it, the Cowork VM continues to serve the old file content. The VM reports a smaller byte count than the host, and content ends mid-word. Remounting doesn't fix it. Reproduced on two independent machines (Windows laptop and Azure Windows Server).
What Should Happen?
Files read from the virtiofs mount should always reflect the current host filesystem state. Host-side modifications should be visible on subsequent reads without requiring a restart. File size in the VM should match the host at all times.
Error Messages/Logs
No error messages — the failure is silent. stat on affected files shows no trailing newline (last byte is mid-character, e.g. 0x6e, 0x75). wc -c reports a smaller size than PowerShell (Get-Item).Length on the host. Mount type: fuse via /mnt/.virtiofs-root/shared/, IO Block: 262144.
Steps to Reproduce
Mount a folder containing a text file in Cowork
Edit that file on the host using any editor (Notepad, Obsidian, or let a sync tool update it)
Read the file inside the VM — shows old content, truncated
wc -c reports old file size
Remount via request_cowork_directory — new mount point, same stale data
Write to the file from inside the VM — change propagates to host (one-way only)
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
Claude Code version: 2.1.78
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Other
Additional Information
This is on claude desktop (cowork)
45 Comments
Found 1 possible duplicate issue:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Additional finding: FUSE metadata cache appears to be keyed by filename
I'm hitting the same issue on Windows (Claude Desktop / Cowork). During debugging, I narrowed down the caching behavior:
File A (88 KB on host) → VM consistently reads only ~61 KB (truncated ZIP, missing EOCD)
Copy File A to File B (different name) on the host → VM reads File B at full 88 KB, no truncation
Delete File A, rename File B back to "File A" → VM serves the old stale 61 KB content again
This suggests the stale size is cached by filename, not by inode or content hash. A brand-new file inheriting the original name inherits the stale cached metadata.
Also note: this is distinct from #28890, which is about the VirtioFS mount dying entirely after idle. In our case the mount stays functional — reads succeed without errors, but silently return truncated content.
Things that did NOT clear the cache:
echo 3 > /proc/sys/vm/drop_caches
fusermount -u + remount
Starting a new Cowork session (new VM instance)
The only workaround is to permanently use a different filename, which isn't practical.
Additional reproduction — secondary drive (S:), same symptoms
Adding my case as a second independent reproduction to prevent auto-closure. This is the same bug.
Environment
S:\Projects\1AM_Brushless_Motors(secondary/shared drive)/sessions/<session-id>/mnt/1AM_Brushless_MotorsReproduction
S:\Projects\1AM_Brushless_Motorsas Cowork workspace — folder contains.mdfilesls -la→ shows only.and..find / -name "PKA_Agent_Methodology.md"→ no resultsAdditional observations that increase severity
The Code tab in the same Claude Desktop session reads the same folder without any issues. This confirms the host filesystem is fine and the problem is isolated to Cowork's VM file bridge. Same app, same machine, same folder, different plumbing — Code works, Cowork doesn't.
File uploads through the chat UI also fail. Uploading
.mdfiles (which should render inline as text) results in only the file path metadata arriving — the file content is not transferred. This means even the upload workaround is broken by the same bridge issue.Empty folders also fail. Unlike #27594 where empty folders worked but populated folders didn't, in this case even a folder with very few files appears completely empty. This is a regression from the previous state.
Files written by Cowork are also invisible to the user. Files that Cowork creates in the mounted folder cannot be viewed, previewed, or accessed through the Cowork UI. The
computer://links and file previews do not work. This means the mount is broken in both directions — Cowork can't read host files, and the user can't see Cowork-created files.Impact
Cowork is completely unusable for file-based work. This isn't a degraded experience — it's a total loss of the core feature. Users paying for Cowork on the Max/Team plan cannot use it for its intended purpose (reading and working with project files). The only "workaround" is to not use Cowork, which isn't a workaround.
Request
Please do not auto-close this as a duplicate. Issues #27594 and #29583 were closed without resolution. This is a critical, blocking regression that makes an entire product feature non-functional on Windows. It needs an owner and a fix timeline.
Reproduced on the following environment:
Device: Lenovo IdeaPad Pro 5i
OS: Windows 11
Client: Claude Desktop (not browser-based)
Client version: 1.569.0 (49894a)
Build date: 2026-04-02T20:01:42.000Z
Issue is reproducible as described. Workaround confirmed: navigating to Claude Code or Claude Chat and returning to Cowork resolves the stale view for that session.
Reproduced on the following environment:
Platform: Windows 11 Cowork desktop app
Trigger: File edited by Cowork session via Edit tool (replace_all), changing file size. Separate scheduled task session later reads the same file and gets truncated content.
Both sessions mount the same host directory =
The main session did NOT write via host-side tools — the edit came from within Cowork itself, meaning even sandbox-to-sandbox writes across different sessions can trigger this
File affected: a markdown file that grew slightly due to a string replacement
Result: Scheduled task session saw truncated file, had to reconstruct and rewrite it
Reproduced on Claude for Windows 1.1617.0 (8d6345) 2026-04-09T16:10:15.000Z. Cowork tab only. Claude Code (via Windows Desktop) is not affected.
Mount filesystem cache invalidation causes stale/corrupted file reads in bash
Files modified on the Windows side appear stale or corrupted when subsequently read by bash through the Linux mount. Windows writes the file correctly — the Linux-side page cache does not invalidate. The bug has three variants depending on file type and the size relationship between the old and new content.
Variant 1 — Truncation (new file larger than cached version): Bash serves the old shorter content; new bytes are silently dropped.
wc -lreports fewer lines than the file actually contains. JSON parse errors fire mid-file at the old EOF boundary.Variant 2 — Null-byte padding (new file smaller than cached version): Bash pads to the old file size with
\x00bytes.json.JSONDecodeError: Extra datafires at the null boundary. Confirmed by reading in binary mode — valid content ends at the correct closing character, followed by hundreds of null bytes.Variant 3 — EOCD corruption (ZIP-based binary files:
.xlsx,.docx,.pptx): PK magic bytes at offset 0 are intact andfilereports a valid format, butzipfile.is_zipfile()returnsFalseand openpyxl raisesBadZipFile. The ZIP End-of-Central-Directory record at the tail of the file is stale. File sizes on both sides appear identical.Root cause: Linux kernel page cache invalidation failure at the mount boundary. The cache only updates when bash writes. When the Windows host modifies a file — whether via a user editor or Claude's Edit/Write tools (which go through the Windows path) — the Linux cache entry is not invalidated and bash reads stale data.
The Read/Edit/Write tools and bash access the same underlying files through different paths with different cache layers. The Read tool always reflects true on-disk content (Windows path); bash reflects the mount cache.
This has also happened to me recently and has been making me pull my hair out. Here is the summary that Claude wrote of what happened in our cowork session.
Subject: Cowork file tools (Edit/Write) silently corrupt files on mounted folder
Environment
Product: Claude desktop app, Cowork mode (not Claude in Chrome, not web)
Host OS: Windows 11
Mounted folder: a local project directory under C:\Users\brode\Documents\ that I selected in Cowork
Model: Claude Opus 4.6
Project: a vanilla JS game with ~90 JS files and ~200 JSON config files
Summary
During a long debugging session, Claude's Edit and Write tools repeatedly produced corrupted writes to files in my mounted project folder. The tool calls returned success. Subsequent Read calls showed the file looking correct from Claude's view. But the bytes actually on disk were broken, and my Windows toolchain (node.exe from a launcher script) failed on them. This caused several hours of extremely confusing debugging because Claude's view of the filesystem disagreed with what Windows was actually seeing.
Corruption patterns observed (all in one session, same mount)
Truncation with same byte count. Claude used Edit to modify launch-gui.ps1. File size stayed at 8217 bytes, but the tail was silently replaced: the file ended mid-sentence at "stays responsive while the use" instead of the correct final [void]$form.ShowDialog(). Same pattern hit build.js (truncated at // Inser) and tools/restore.bat (truncated mid-word at i inside a for /f block).
NUL-byte padding. js/entity-render.js ended up with approximately 573 trailing NUL bytes. node --check on the individual file tolerated them, but the project's bundler concatenates all JS modules and the NULs landed mid-bundle, producing a syntax error at a synthetic line far past any real code.
Stale trailing bytes after valid content. data/world/seasons-config.json had valid JSON followed by a literal } } tail from an older version of the file. Python's json.load and Claude's mount-side view accepted it (trailing content read as whitespace). Windows's JSON.parse saw the real disk content and failed with "Unexpected non-whitespace character after JSON at position 49275."
Key evidence that this is a tool bug, not user error
Corruption was non-deterministic within a single session. Some Edit calls worked correctly. Others silently corrupted. Same tool, same file, same session.
Edit returned success in every case. There was no error or warning to indicate a partial write.
Claude's Read tool, after the corrupted write, returned the intended content — not what was actually on disk. So Claude could not detect its own broken writes by reading them back.
The Linux-side sandbox (node build.js --dev run by Claude through bash) passed cleanly, while the exact same command run from my Windows launcher failed — because the mount layer was serving different bytes to the Linux sandbox than what Windows was actually seeing on disk.
This reproduced with at least three corruption patterns (truncation, NUL padding, trailing stale bytes), suggesting the bug is in the write path of the mount layer rather than a one-off flake.
Workaround that worked reliably
Once we stopped using Edit/Write entirely and switched to writing files via bash with an atomic protocol — write to a temp file, fsync, then os.replace to rename — every write persisted correctly. So the issue is specifically in how the Edit and Write tools interact with the mounted-folder write path, not in the mount itself.
Impact
Roughly 3 hours of debugging across two sessions before we identified the root cause. The failure mode is maximally confusing because (a) Claude's own reads confirm the write looked fine, (b) Linux-side builds pass, and (c) the launcher just says "Build failed (exit 1)" with no context. A user who doesn't ask Claude to instrument the failure will have no way to diagnose this.
Suggestion
Either fix the write path so Edit/Write atomically persist to mounted folders, or have the tools verify writes by reading the file back byte-for-byte after every write and returning an error when the bytes don't match. At minimum, a warning banner when Cowork detects it's running against a mounted folder on Windows would have saved hours here.
Did some more testing, here's a simple summary, easily tested with text file editing:
Root cause: The virtiofs mount does not update file size metadata when Windows changes the file size after the file is read/cached in the VM. Content within the original byte range syncs correctly, but size changes in either direction are not reflected on the Linux side.
Case 1 — User grows a file in Windows: VM sees the updated content up to the original byte count, then truncates. Bytes added beyond the original size are invisible to VM. Confirmed with cat -A showing a line cut off mid-word at exactly the original byte boundary, and wc -c still reporting the original size.
Case 2 — User shrinks a file in Windows: VM retains the original byte count. File seen in VM now has null bytes (^@) padded to the old file size. Confirmed with cat -A and wc -c.
Things that did NOT fix it: redownloading the VM bundle, deleting all VM sessions, cleaning cache, updating to latest Cowork Desktop (1.2581)
Workaround: Never edit a file in Windows, must create a new file with a unique (uncached) filename.
Possible fix (not accessible to users): launch virtiofs with cache=none
Additional data points confirmed on Windows 11 desktop app:
---
Adding evidence from ~3 weeks cowork use, including the past week using it basically nonstop. A surprising chunk of that time was spent either encountering this problem, or building a skill to work around it which i iterated several times as more information emerged. Notably the issue occured >3 times when asking Claude to compile our notes for submission.
TL;DR
caton the same path shows a truncated reality.git initproduces a 54-byte all-NUL.git/configand skips.git/objects/info|pack/creation..git/indexindependently NUL-pads during normal commit operations. Neither outcome is in the current thread./mnt/.auto-memory/(virtiofs-fuse) remained invisible inside the sandbox for ≥3 minutes, with the in-VM mtime stuck two days stale**. Host-side inspection confirmed the file was current.cat > file <<'EOF' … EOFfrom bash finally landed cleanly.virtiofsd --cache=none, versus the currentautodefault (1-sec metadata TTL, per the QEMU docs).A "not-alone" check: this thread has 9 👍, 4 independent-user repros, and 7 closed duplicates (#40191, #40264, #41702, #41710, #42520, #42913, #43523) — but no Anthropic engineer response in 27 days. #42520 was closed by its reporter as a self-identified duplicate within 90 minutes of opening. The symptom class affects core agentic workflows (git, plugin manifest edits, persistent memory files).
Full documentation follows.
---
Environment
| Field | Value |
|---|---|
| Host OS | Windows 11 (build: redact to actual build at submission) |
| Product | Claude Desktop for Windows, Cowork (research preview) |
| Claude Code (inside sandbox, pre-installed at
/usr/local/bin/claude) | 2.1.x || Guest OS | Ubuntu 22.04.5 LTS |
| Workspace | A folder on the D: drive (NTFS), mounted via Cowork into the sandbox |
| Mount stack (observed from
mountinside the sandbox) |bindfs on /sessions/<id>/mnt/skills type fuse.bindfson top of/mnt/.virtiofs-root/shared/…; directvirtiofs-fuseon/mnt/outputs/,/mnt/uploads/,/mnt/.auto-memory/|| Reproduces | Every Cowork session of the last month. Not intermittent — routine on small-config edits, git, memory writes |
| Does not reproduce | Same Windows host, same D: drive, driven by Claude Code natively (no FUSE layer). All seven claims in this comment were re-run and confirmed absent outside the sandbox. |
The Claude Code control comparison is what makes me confident the bug lives in the sandbox's FUSE bridge, not in the host OS, antivirus, filesystem, or user profile.
---
New failure modes not yet in this thread
1. Bindfs-specific small-file silent truncation (guest-side writes)
Sub-1 KB modifications to existing files on
/mnt/skills/via the sandbox's built-in Edit and Write tools can silently truncate mid-token. Tool reports success. Read returns the intended content (shared cache). Bashcaton the same path shows the truncated reality. On bindfs, bash is authoritative — the file on disk really is truncated, and a downstreamgit addwill commit the truncated version.Examples from my sessions:
.claude-plugin/marketplace.json— intended ~2 KB, actual 994 bytes, truncated mid-"keywords"array..claude-plugin/plugin.json— 742 bytes, truncated at"keywords": ["c(mid-token)._decisions.md(the file for this very draft) — Edit reported success, file stayed unchanged; full-content Write reported success, file stayed unchanged; bash heredoc rewrote cleanly. Confirmed three times in a row bywc -candgrepon the intended new section header.<details>
<summary>Minimal reproduction (click to expand)</summary>
</details>
2.
git initproduces a 54-byte all-NUL.git/config, and skips object-dir creationRunning
git initin a fresh directory on a bindfs mount:.git/configis 54 bytes of\x00with no text content..git/objects/info/and.git/objects/pack/are missing entirely.git add/git commitfail.<details>
<summary>Minimal reproduction</summary>
Recovery requires heredoc-rewriting
.git/configto a valid core block andmkdir -p .git/objects/info .git/objects/pack. Running the samegit initon the same D: drive outside Cowork (Claude Code, Git Bash, PowerShell — all tried) produces a valid 112-byte text.git/configand the expected object dirs.</details>
3.
.git/indexNUL-padding during commit preparationIndependent of init — on a long-running repo, certain
git update-index/commit paths that do an atomic-rename write to.git/indexcan produce an index file that is entirely NUL bytes (noDIRCmagic signature). Observed concretely: a 40,424-byte all-NUL.git/indexafter agit update-index --cacheinfo. Every subsequent git command fails witherror: bad signature 0x00000000 / fatal: index file corrupt.Recovery:
mv .git/index .git/index.corrupted.<tag>(unlink is denied on bindfs — rename is the workaround), thengit read-tree HEADto rebuild the index from the last commit. Verify the new index begins with theDIRCmagic (xxd -l 4 .git/index).The concerning bit: an agent or operator without this context would reasonably try
rm -rf .git && git init— which on this environment destroys all local history including the unpushed commit containing the current session's work, and hits failure-mode #2 on thegit initattempt.4. Cache lag quantification — days of mtime, not seconds
This extends the thread's "stale reads" claim with a quantitative upper bound.
Directly observed 2026-04-21 on
/mnt/.auto-memory/(virtiofs-fuse): a ~2.7 KB Write completed at host-side mtime 00:33. Three minutes later, bash inside the sandbox still reported the pre-Write size (~400 bytes smaller) and an mtime from two days earlier (2026-04-19). Host-side inspection via Windows confirmed the file was current and intact. The cache-invalidation window isn't a sub-second coherency gap — in this class of case it is effectively unbounded until something forces a revalidation.@brenny1102's upstream observation that the cache is filename-keyed, and @kaseylcade's "switch to Code tab and back" workaround, are both consistent with needing an explicit revalidation trigger for the guest FUSE client.
---
Workaround limitations
The workaround in #42520 ("avoid MCP tools for file writes; use only the sandbox Read/Edit/Write tools, since these go through the FUSE mount and stay consistent with their own writes") addresses the host → guest stale-read direction but does not help with the guest → host bindfs write direction documented in §1 above — the Read/Edit/Write tools themselves are silently truncating through bindfs. In this draft's own case, the file I could not write cleanly was the draft of this very comment.
For git specifically, no sandbox-side workaround is complete.
gitsubprocesses write.git/indexand object files through bindfs directly, bypassing the agent's Read/Edit/Write entirely. The current mitigation I use is to commit from inside the sandbox (with identity injection viagit -c user.name=… -c user.email=…) and then hand thegit pushback to PowerShell on the Windows host — defeating much of the point of agentic version control.The one reliable bindfs write path I have found for modifying existing files is bash heredoc:
cat > path <<'EOF' … EOF. This bypasses the tool layer entirely and has not truncated in ~20 documented uses. Verification of every tool-layer write to a bindfs mount viawc -c+ parser round-trip beforegit addis now a hard prerequisite in my operating playbook.---
Candidate remediation
Per the upstream virtiofsd documentation (https://qemu.weilnetz.de/doc/7.1/tools/virtiofsd.html), the
--cacheflag directly governs this behaviour:The symptom set in this thread is consistent with
--cache=auto(default) combined with a bindfs layer on Windows hosts that appears to compound the coherency window. A Cowork-level session toggle for--cache=nonewould eliminate the stale-read symptom class at a throughput cost. The bindfs write-truncation surface (§1) would need separate investigation — I suspect it lives in the bindfs layer's own write path rather than in virtiofsd, but I cannot confirm without access to the adapter configuration.For architectural context: public reverse-engineering of Cowork on macOS hosts (Pluto Security, April 2026) shows Apple Virtualization.framework + virtiofs with no bindfs layer; #42520's stack diagram explicitly shows
NTFS → virtiofs → bindfs → sandboxon Windows. If bindfs is a Windows-host-specific adapter translating NTFS semantics into POSIX, it may well be separable from the virtiofs cache issue and responsible for a large share of the write-truncation reports — worth checking whether §1 reproduces on macOS hosts. I cannot test this directly.---
Request
--cache=autodefault hypothesis at the virtiofsd layer. If that's the root cause of the stale-read class, the user community can at least design around a documented coherency window.--cache=none+ any analogous bindfs adjustment).Happy to provide additional diagnostics on request: full
mountoutput, rawstraceof a failed unlink, a fault-injection harness for the bindfs truncation mode (§1), and Claude Code-vs-Cowork side-by-side replication logs for any of the seven failure modes on this host.Reproducing on Windows 11, OneDrive-synced workspace, with xlsx files
Setup: Cowork workspace pointing to a OneDrive-synced folder (C:\Users\...\OneDrive\...).
Workflow: read an xlsx file from the mount, modify it in the sandbox with openpyxl, cp the result back to the mount path.
Symptom: On the next run (new session or same session after a write), cp from mount to sandbox produces a file with a valid PK magic header but no EOCD record (data.rfind(b'PK\x05\x06') == -1). File size observed via sandbox is smaller than the actual file on Windows (e.g., 20,633 bytes vs ~37,000 bytes). openpyxl.load_workbook() raises BadZipFile. The file on Windows is healthy — correct size, opens normally in Excel.
Workaround: Restarting Claude Desktop flushes the mount cache; subsequent reads return the correct file. Retrying cp + load without restarting does not help — the mount consistently returns the stale version until process restart.
Pattern: Consistent with the one-way sync described here. VM writes propagate to host correctly, but host-side changes (including those written by the VM itself via the mount) are not reflected back. The snapshot appears frozen at the pre-write state.
Impact: Any read → modify → write → read loop is affected. For zip-format files (xlsx, docx, etc.) this manifests as BadZipFile rather than just stale content, since the missing EOCD record makes the file unreadable. Silent failure, no error from the cp or Write tool.
My new and improved workaround is to direct Claude (via a skill) to do all file edits in a scratch folder that only exists in the sandbox.
At end of session Claude copies to windows, and I confirm manually that the edits have landed.
Adding repro evidence from a Cowork session today (Windows 11). Same bug pattern; one new finding worth highlighting:
A rename within the sandbox (
mv file.md file-c.md) forces cache invalidation and reveals the true on-disk state. Makes the bug recoverable from inside the sandbox, but only at the cost of a permanent filename change.Today's repro:
.mdfile in a host-mounted folder. Edit tool returned success.wc -l,stat,tail,grep -c,md5sum) all reported the file unchanged at the pre-edit size and md5.touch + sync + sleep 2. Bash view partially updated and showed the file ending mid-sentence -- I initially misdiagnosed this as a partial write / truncation.echo "..." >> filereported exit 0 butgrep -cfor the appended marker returned 0 -- bash could not see its own write either.mv file.md file-c.md+ sync + sleep 2.Two specifics that add to the original report:
wc,stat,tail,grep,md5sum) are part of the failure surface, not a reliable diagnostic against it. When the Read tool and bash disagree, neither view is presumptively true until a rename-bump forces a fresh dentry/inode lookup.The in-sandbox rename workaround keeps work moving but ratchets filenames and any cross-file references go stale -- not a substitute for a fix at the virtiofs-to-FUSE bridge layer.
I run a test with every desktop app update, and it still occurs. To be clear, this has nothing to do with OneDrive or Excel. The most simple repro is to create a textfile on a local folder in Linux via cowork, edit it (make it larger or smaller) in Windows Notepad, then check the contents and filesize in Linux.
My workaround: Import all my cowork projects into claude code and run it from there.
Yeah I've moved to Claude Code too.
I think Claude Cowork will be less intimidating for all my less technical colleagues though so I continue to watch for the fix 👀👀👀
Additional findings: remount behavior and attr cache staleness (Windows, v2.1.110)
I did some hands-on testing of the virtiofs FUSE mount caching behavior in Cowork on Windows. Here's what I found — it partially contradicts the original report's claim that remounting doesn't help.
Environment
/mnt/.virtiofs-root/shared/c/claude→/sessions/.../mnt/claude)rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_otherentry_timeout,attr_timeout, ornegative_timeoutspecified (defaults to indefinite caching)Key finding: page cache vs attr cache inconsistency
After remount, file content (page cache) is refreshed but file metadata / stat (attr cache) is NOT refreshed. This means:
cat filereturns the correct latest content after remountstat filereturns stale size, mtime, and ctime from a previous statels -lashows stale metadataThis is a partial fix — the data itself is usable after remount, but any tool or workflow relying on
stat(file size, modification time) will get wrong information.Practical impact: diff and other stat-dependent tools break silently
Because
statreturns stale metadata (wrong size, wrong mtime) whilecatreturns correct content, any shell workflow that depends on file metadata will produce incorrect results:diff— compares files using size/mtime as a fast-path; stale metadata can cause it to skip comparison or report false differencesrsync— uses mtime + size to detect changes; will miss host-side modifications entirelymakeand build tools — rely on mtime to determine what needs rebuildingfind -newer— returns wrong results because mtime is frozengit status/git diff— stat-based change detection fails; git may not see that files have changed on diskls -lt(sort by time) — shows wrong orderingThis makes it effectively impossible to write reliable shell scripts that detect or reconcile differences between the VM and host filesystem state. The only workaround is to compare file content byte-by-byte (e.g.,
cmp,sha256sum), which defeats the purpose of having metadata.Suggested fix
The FUSE mount should specify explicit cache timeouts. Currently no
entry_timeoutorattr_timeoutis set, which means the kernel caches indefinitely. Setting these to0(or a short TTL like a few seconds) would fix both the content and metadata staleness:Alternatively, the remount operation should ensure both page cache and attr cache are invalidated.
_Claude Assisted Bug Report_
Adding evidence from a Cowork session on Windows (May 10–11 2026) using a OneDrive-synced project folder. Same symptom as the original report — some additional details that may help narrow the fix.
OneDrive-synced folder as a concrete trigger
The folder selected for the Cowork session was under
C:\Users\<user>\OneDrive - <tenant>\…\<project>\. Both Cowork-generated files and host-side edits to those files flow through OneDrive's sync layer. The staleness manifests the same way the OP describes regardless — host writes don't reach the VM..docxfiles show a specific corruption patternWhen the host modifies a Word
.docxfile in the mounted folder, the bash-visible version of that file:PK\x03\x04) and contains all 27 expected docx parts as local file header + compressed data recordsPK\x05\x06trailer); the tail of the file is zero-paddedpython-docxfails to open withPackageNotFoundErrorzipfile.is_zipfile()returnsFalsezip -FF source.docx --out recovered.docxsuccessfully reconstructs the central directory from the surviving local file headers; the recovered file opens cleanly in python-docxThe fact that local file headers and entry data survive but the central directory and EOCD are absent suggests the cache is serving a partial / mid-write snapshot of the docx — not a fully-baked truncation at a byte boundary. Worth flagging as a distinct manifestation from the mid-word text-file truncation in the OP.
Staleness window observed: 3+ hours, single session
Single Cowork session, single mount, no remount. The bash-visible mtime for an affected file stayed pinned at the first-read value for the entire 3+ hour observation window, across multiple distinct host-side Ctrl+S save events with confirmed-different mtimes on the Windows side. Specifically:
2026-05-10 19:05:14 UTC2026-05-10 22:21 UTC(3h 16m later)19:05:14 UTCevery timeThis exceeds the
cache_duration_s = 3600figure identified in #55877, which suggests either an additional cache layer or that the cache simply never refreshes within a session.Disproof of OneDrive Files-On-Demand as the cause
OneDrive FoD would force a fetch on read access, so
cpfrom a stub file would always produce the fully-hydrated content. We tested this directly:cpfrom the bash mount path produces a byte-identical stale copy (same partial-file pattern as the source). So the staleness is at the Cowork mount layer, not OneDrive FoD's lazy-hydration.User confirmed on the Windows side that the OneDrive icon for the affected file shows the solid "always available on this device" indicator, not the cloud-only or syncing variants.
Cache-consistency asymmetry confirmed
Per the OP's parenthetical "change propagates to host (one-way only)" — confirmed at length. Files generated by Cowork via python-docx are visible to Word on the host immediately. Files modified by Word on the host are never visible to Cowork. The mount cache is invalidating correctly on internal (sandbox-side) writes but not on external (host-side) writes.
Workflow impact
Breaks any round-trip pattern where Cowork generates an artifact, the user applies editorial polish in a host application (Word here, but presumably any host editor — Notepad, Excel, etc.), and Cowork needs to re-read the modified file to extract the user's edits or sync a sister representation. There's no recovery path within the session. We were forced to abandon the round-trip approach and fall back to: (a) Cowork generates, user takes over with no return path, or (b) user describes edits in chat for Cowork to re-apply against a different source of truth.
Cross-references
cache_duration_s = 3600in the rclone-filestore mount as the root cause; our 3+ hour staleness exceeds that figure, suggesting an additional cache layer or no in-session refresh at allvirtiofsdwithcache=noneon workspace mounts as the fixHappy to provide further diagnostic data (additional stat outputs, hex dumps, the
zip -FFrecovery procedure that consistently worked, etc.) if it helps. The Cowork session transcript captured a complete diagnostic trail._Claude Assisted Bug Report_
Confirming this is still reproducing on current Cowork (Claude Code
2.1.138, bindfs 1.14.7 in the sandbox). Coordinated PowerShell-vs-sandbox test reproduces the stale-content behavior exactly: sandbox view stays at the last sandbox-originated state for >111 seconds after a host-side rewrite, with no manual sandbox-side flush working (ls,stat, freshopen(),touch).Posted detailed analysis on #55206 tying the read-side cache-coherency cluster (#38993, #41710, #42520, #45433, #50873) to the write-side EPERM cluster (#55206). Both reproducible simultaneously on the same Cowork bindfs mount — independent bugs with independent root causes, but co-located in the same Cowork mount-setup code.
Another data point for this issue from a Cowork-on-Windows project (Hyper-V virtiofs + bindfs FUSE), plus three workaround observations that may help anyone hitting this while waiting for a fix.
We hit exactly the symptoms in your report — files ending mid-character,
wc -creporting a smaller size than the host, remounts not helping — and originally misdiagnosed it as a write-time clamp on the sandbox side before a controlled-reproducer pass revealed the same diagnosis you, #42520, #41710, and #40264 all converged on: the FUSE kernel attr cache holdsst_size(and mtime, and mode) from the last sandbox-originated operation, andcatreads fresh data but stops at the cached EOF — which mimics a truncation symptom exactly.Three things that didn't come up in the existing reports but were useful for us:
1.
touch -mis silently absorbed. The obvious "just bump the mtime to invalidate the cache" workaround does nothing — the kernel cache eats the syscall without round-tripping to the FUSE daemon, andstatdoesn't even show the new mtime afterward. Worth noting because it's the first thing most people try.2.
mv X X.tmp && mv X.tmp Xis the only per-file refresh that fully works for a non-root sandbox user. The matrix we ended up with:| Mechanism | Refreshes size? | Refreshes mtime/mode? | Notes |
|---|---|---|---|
|
mv X X.tmp && mv X.tmp X| ✅ | ✅ | Forces dentry re-lookup → fresh GETATTR. Observable as a Windows-side rename round-trip. ||
chmod 700 X(any chmod) | ❌ | ✅ | Partial — mtime/mode only. ||
touch -m X| ❌ | ❌ | Silently absorbed by the cache. ||
echo 3 > /proc/sys/vm/drop_caches| n/a | n/a | EPERM in the sandbox. ||
/sys/fs/fuse/connections/N/abort| n/a | n/a | Also root-only. |The rename trick is essentially the only escape hatch from inside bash, and it has a real cost (file watchers see it, atomic-rename-aware tools may react). #40264's "copy with a new filename in Windows Explorer" is the host-side analogue of the same dentry-rebuild insight — both work because the cache is keyed by path/dentry, not by underlying file content.
3. Supporting your framing that this is not MCP-specific. #42520 framed the cascade-corruption-to-host path through MCP host-side writes. We hit the same cascade in a project that uses no MCPs at all — the desktop-app file tools (
Read/Write/Edit) write to Windows correctly through the desktop-app bridge, but those writes don't invalidate the bash-side FUSE attr cache either. So the corruption chainbash-read (stale) → process → tool-write (full new content)produces the same on-disk NTFS truncation #42520 calls out, with no MCP involved. The wider framing in this issue ("any process — editor, sync tool, script") is the right one; our experience just adds another host-side writer to the list.For anyone landing here looking for a project-side mitigation while waiting for a fix: we ended up with a four-line operational rule — (a) use the file tools as the primary I/O surface, (b) never write back content sourced from a bash read of a pre-existing file, (c) keep all
gitoperations on Windows (.git/indexis the canonical case), (d) trust the file tool's view overcat/statwhenever they disagree. New files (no prior cache entry) are universally safe. (Caveat: #41710 reports a case where the Read tool also returned a truncated view, so rule (d) isn't iron-clad — but in our reproductions the Read tool consistently saw the real on-disk state when bash didn't.)Thanks for the original report and the two-machine reproduction — the fact that this was already filed with a precise diagnosis is what let us shortcut the investigation once we found this thread.
---
For context: both the original investigation and this comment were produced in a Claude Cowork session using Claude Opus 4.7, against a Hyper-V virtiofs + bindfs mount on Windows 11.
Additional findings — per-path cache lock confirmed via 18 empirical tests
Confirming this bug from a Max plan user perspective. Reproduced extensively over 2026-05-17 and 2026-05-18 across both OneDrive and plain local folders (
C:\WorkTest\). Bug is NOT OneDrive-specific — it's purely in the mount layer's caching logic, regardless of underlying storage backend.Refined architectural model
Mount layer maintains a per-path cache locked at first read:
BadZipFilefor.xlsm/.xlsx/.docx/.zip; silent data loss for.csv/.txt/.json/.md/.html(most dangerous case — no error signal at all).Validated operational matrix (18 tests)
| Operation | Cache state |
|-----------|:-----------:|
| File modified by Windows (Excel save) after mount init | ❌ Truncated to old size, content partially updated |
| Rename round-trip in Windows | ❌ Stale, byte-identical to pre-rename |
| Move-out + move-back via Windows | ❌ Stale |
| Move-out + modify outside + move-back (same name) | ❌ Stale; modifications invisible |
| Delete + replace with different file (same path) | ❌ Size frozen; truncated |
| Sandbox
shutil.move(rename) of stale-cached file | ✅ Fresh at destination || Sandbox
shutil.moveback to original path | ✅ Original path cache refreshed || Sandbox
open(p,'wb').write()(own write) | ✅ Write-through, full cache update ||
os.removefrom sandbox | ❌PermissionError— blocked |Triple-confirmed truncation pattern
Same pattern reproduced on three different
.xlsmfiles (БМ,01,001) in same session:BadZipFile(EOCD truncated at byte N₀ when real file is N₀+25)Working workaround (sandbox-only, no user upload needed)
Verified end-to-end on real master
.xlsmfiles (ИБ.xlsm: 704,035b stale → 826,747b fresh after refresh).Suggested fix priorities
Why this matters
For ZIP-based formats,
BadZipFileis loud and detectable. For plain text formats (CSV, JSON, source code, configs), truncation is silent — the agent processes incomplete data without any error signal. This is a data integrity issue, not just UX friction.Full details (with email reference and complete reproduction): "[Cowork BUG follow-up v4 — FINAL] Per-path cache locks at first read. Full architectural model with reproductions." sent to support@anthropic.com on 2026-05-18.
I have been using Claude Cowork to maintain a Karpathy styled LLM wiki in support for my design and research work, so each session involves many substantial file writes and edits. This bug has become a serious problem as it is quite common for a file to end up being silently truncated, which is only discovered during follow-up checks.
My work-around to this problem was to instruct Claude to create a Python script to write and lint files instead of using its common tools. So far this has worked, but it is not ideal.
NOTE: the following report was prepared (and suggested) by Opus 4.7 at the end of a Cowork session:
TL;DR: On Cowork (Windows 11 / virtiofs), the Edit and Write tools
intermittently fail silently — the file ends up truncated, or unchanged,
while the tool reports success. ~9 files hit this in a single session,
undetected until an end-of-session lint.
Adding session data that goes beyond the mid-word host→VM staleness already
described in this thread.
Observations — all verified out-of-band with
wc -c/tailin bash:off — sometimes mid-word, sometimes on a clean newline boundary so it still
looks structurally valid. (b) Silent no-op: file left byte-identical to
before; the edit simply didn't apply. Both return a normal success result.
twice, both reported success, file unchanged (61966 bytes) both times. It
applied only after switching to a bash/Python write.
~14 writes via
cat >>heredoc and Pythonopen().write()had zerofailures. The fault tracks the Edit/Write tool path — not a globally broken
mount.
top was left with its final paragraph truncated. This suggests the
whole-file rewrite is what gets truncated, not the edited span.
session. Not a rare edge case.
Impact: silent data loss on a routine operation. The tool's success
message cannot be trusted; detecting the failure requires byte-level
verification via bash after every write.
Environment: Claude Cowork, Windows host, virtiofs FUSE mount, files in the
mounted workspace folder. Intermittent — no deterministic repro.
Adding a cross-reference to a parallel report and a CLI-side defense.
The recently filed #62932 (2026-05-27, marked P1 by the reporter) is the same shape on a Cowork session mounting a Windows host folder at
/sessions/<id>/mnt/<folder>/. Same selective wedge: once a file is read,statsize/mtime and content stay frozen for the rest of the session; working-tree git walks (git status/add/commit) silently return phantom or stale results; ref-walking commands (rev-parse/log/show) stay clean because they don't touch the wedged dentry cache; Cowork's first-class file tools (Read/Edit/Write) bypass FUSE and remain authoritative. On the host shrinking a file (e.g.gh pr merge --delete-branchshrinking.git/config), the VM serves the valid prefix + trailing NUL padding to the old size, breaking parsers like git's config reader.I cannot fix the FUSE layer from operator side, but for CLI sessions on the same machine that occasionally run inside the Cowork mount path I shipped a PreToolUse defense today (2026-05-28) that detects this case before a dangerous working-tree git op runs:
cowork-fuse-staleness-watcher.sh(PR #410, 25 tests passing).Design:
Bashtool calls with a working dir orgit -C <path>argument inside/sessions/<id>/mnt/status,add,commit,diff,restore,stash,checkout -- <path>,clean,ls-files)rev-parse,log,show,cat-file)exit 0(advisory only); env vars to silence (CC_COWORK_FUSE_QUIET=1) and log (CC_COWORK_FUSE_LOG=…).git/configitself has been corrupted by the NUL-padded shrink (rewrite viacat > .git/configinside the sandbox)It is not a fix — the underlying virtiofs caching is server-side from the operator's perspective — but it catches the most common silent-corruption foot-gun (
bash git commitover a wedged working tree) before it lands a stale commit.If a Cowork-internal fix is in scope and being tracked elsewhere, please link it here; if not, an Anthropic-side acknowledgment that the working-tree git walks are an unsafe surface inside Cowork mounts (so that operators know to switch to first-class file tools or ref-only ops) would already be a meaningful operator-facing signal.
Workaround: ZIP comment padding
TL;DR: Pad your openpyxl-saved
.xlsxfiles to ~60KB using the ZIP EOCD comment field. Host-saved files (from Excel/any editor) will then be fully readable by the VM as long as they're smaller than the padded size.---
Root cause (as I understand it)
The virtiofs mount caches the file size from the last VM-side write. When the host later saves a larger file, the VM truncates reads at the old cached size — no EOCD, no central directory, unreadable ZIP.
The workaround
After every
openpyxlsave, extend the file's ZIP EOCD comment field to pad the total size to ~60KB. When the user saves from Excel (which typically produces a smaller file than my openpyxl build), the host file fits entirely within the VM's cached size and comes through intact.Call
apply_zip_padding(path)after everywb.save(path).Caveats
target_kbif needed.\x00). Excel ignores the ZIP comment entirely and will strip it on save, which is fine — the next VM write re-applies it.Hope this helps while a proper fix lands.
Additional reproduction data from a long-running production session (2026-06-04, Cowork sandbox).
Environment
Observed symptoms
stat <file>returns successful inode/size/mtime[ -f <file> ]test returns truels -la <file>outputs BOTH "No such file or directory" AND the file entry in the same commanddd if=<file> bs=1 count=10fails with "No such file or directory"git config --listfails withfatal: error processing config file(s)git checkout -b <branch>fails withfatal: unknown error occurred while reading the configuration filesWorkarounds tested
Operational impact
Workaround in our internal regulation
git config --listfailsgit config --list || exit 1injected at top of all relevant scriptsNote: closed-as-duplicate #45433 reports the same root cause but has no linked parent issue. Subscribing here for updates.
New evidence: the read-cache is the whole bug, and the host write tools are innocent
Gathered from inside a live Cowork sandbox on 2026-06-11 (Claude Code 2.1.x, bindfs 1.14.7, kernel 6.8.0-124), with the host side verified by the operator in PowerShell on NTFS. Headline: a coordinated sandbox-vs-NTFS test shows the desktop-app file tools write correct bytes to disk every time. The "Edit/Write byte-conservation truncation" reported in #53940 is this stale read cache misread as a write bug.
What was tested
Three scratch files were created from sandbox bash (so the guest cache holds a known size), modified with the desktop-app host-side tools, then read back two ways: through the sandbox FUSE mount, and on NTFS directly via PowerShell.
| File | Operation (host tool) | Sandbox FUSE view | NTFS ground truth | Verdict |
|------|-----------------------|-------------------|-------------------|---------|
| f1 | Write shorter content over a 196 B file | 196 B = 52 B new + 144
\x00| 52 B, clean, no nulls | disk correct; sandbox stale || f2 | Edit adding ~108 B to a 45 B file | 45 B, growth dropped | 154 B, all content present | disk correct; sandbox stale |
| f3 | Write a new 307 B file | 307 B intact | 307 B intact | correct both views |
The sandbox view reproduces #53940's signature exactly: post-edit byte count frozen at the pre-edit size, shrink padded with nulls, growth clipped at the tail. The NTFS side proves those bytes never reached disk in that form. The write was faithful; the read-back used to verify it is what lies.
Why this matters for #53940
That issue concludes the tools "silently truncate via a byte-conservation buffer cap" and recommends verifying every write with
wc -cin bash because "the Read tool returns the in-memory buffer and lies." This test inverts both claims. The write path is correct; the bashwc -creads through the stale guest cache and reports the pre-edit size, which is the false truncation signal. The Read tool (which round-trips through the desktop-app bridge, not the guest FUSE cache) was the more accurate channel here.Root cause (consolidating this thread's own evidence)
A guest-kernel FUSE attribute cache with effectively unbounded validity that no host-side write invalidates. The mount carries
default_permissions,allow_otherand no cache-bounding options; once a path'sst_sizeis cached from the last sandbox-originated operation, every later read clamps at that size.catreads fresh bytes but stops at the cached EOF, indistinguishable from truncation.The cache's shape, already pinned down in this thread, all points the same way:
mv X X.tmp && mv X.tmp Xis the one unprivileged escape (AcId9381).touch -mis absorbed without reaching the daemon.drop_cachesandconnections/N/abortare root-only (EPERM in-sandbox), remount doesn't help, and a fresh Cowork VM still serves the frozen view (#45433), so the cache lives below the per-session mount.This is textbook NFS close-to-open territory, and the classic fix applies.
Recommended fixes, increasing effort
statand surface a mismatch instead of reporting plain success. The silent success is what converts a view bug into data loss in the read-modify-write cascade (#42520).attr_timeout=0,entry_timeout=0on the bindfs re-export and revalidate-on-open at the virtio-fs layer (--cache=auto/never, notalways; no FUSE writeback cache). Read-only mounts (uploads, skills) can keep aggressive caching; they are the only mounts where the never-changes-externally assumption holds.ReadDirectoryChangesW) and forward change events into the guest as FUSE notify / virtio-fs notifications to drop cached attrs and pages on the affected path.stat/wc -cmay not, until (2) or (3) lands. This is the reverse of the guidance currently circulating in #53940.Path-presentation aside (separate, minor)
The outputs directory the harness presents to the agent (
...\Roaming\Claude\local-agent-mode-sessions\...\outputs) does not exist at that literal path on the host. The MSIX package redirects it into the container at...\AppData\Local\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\.... Worth documenting so operators running host-side verification find the real bytes instead of a missing path.Limits (stated so they are not overclaimed)
Three small files, one session, the virtio-fs
outputsmount, current build. It proves the host write tools wrote correct bytes here and the sandbox read view was stale in the documented pattern. It does not prove the host tools are safe on the bindfs project re-export or at all file sizes, and it cannot separate the guest kernel attr cache from a host-daemon cache from inside an unprivileged sandbox. The fix recommendations target the layer this thread's collected evidence implicates; confirming which cache holds the staleattr_validis an Anthropic-side check with daemon logs or root in the guest.Hello guys, its mid june and this bug still hoards in the wild. Cowork reads always comes out buggy, I need to instruct Claude to ALWAYS read files fresh in windows since ALWAYS the version it copied to mount (on my app data folder, I found it) is provided by an older version
It already corrupted a jupyter notebook of mine while editing (dont know why) but luckly it wasn't that important and I could rebuild it purely by luck
But this needs to be corrected. It still existis on Cowork on Windows (I only use in windows, dont know if this happends on other SOs)
Also there is any way for me to connect my cowork onto my WSL distro inside windows? Thanks
Also hitting this on Windows (Claude Desktop / Cowork) with an Obsidian
vault as the mounted folder, can confirm the report.
Reproduced reliably: when an existing file in the mounted folder is changed
on the host, reads inside the VM keep returning the OLD byte count and the
content is truncated mid-word.
wc -cshows the pre-edit size, the inode isunchanged, and
sync, waiting several seconds, and remounting all fail torefresh it. Writing the same content to a NEW filename reads back correctly.
The impact is bigger than it looks: the truncation is silent, it propagates
if the stale file is copied within the VM (the copy is truncated too), and it
makes the agent repeatedly chase "errors" that are pure cache artifacts,
burning a lot of my time and tokens every single session.
Would really appreciate this being prioritized.
Confirming this on Windows 11 (Claude Desktop, Cowork mode), same mount stack (bindfs over a virtiofs share of C:).
Real-world repro: I have Claude update one .xlsx spreadsheet once per day. After Cowork writes the file and it's re-saved/persisted on the Windows side, the next session can't open it (zipfile.BadZipFile, "File is not a zip file"), even though Excel opens the same file fine on the host.
On-machine diagnostics match this issue exactly: stat shows a frozen mtime, so host-side re-saves are invisible to the sandbox; the affected files are full-size, non-sparse, local NTFS (ruling out OneDrive/placeholders); the tail has no valid ZIP end-of-central-directory record, and since an .xlsx is a ZIP whose central directory lives at the end of the file, truncation makes the whole workbook unreadable; files Cowork never wrote (backups, unrelated copies) read fine; a brand-new filename reads fine; and reusing the old name (even after delete + recreate) re-serves the stale view, so the cache is keyed by filename.
Impact worth flagging: this disproportionately breaks recurring "update the same file every day" workflows (trackers, logs, dashboards), which hit the write -> host-change -> re-read pattern every cycle, whereas one-off tasks rarely do. The read-modify-write variant is genuinely dangerous, since writing back the truncated view propagates corruption onto the real host file. Reliable workaround for now: give the sandbox a fresh filename each session, and never write back a file that didn't open cleanly.
Confirming...
Environment
/mnt/.virtiofs-root/shared/...What's broken
Files on a mounted local folder can't be read reliably through the Cowork virtiofs/FUSE
mount — both text (e.g. a Python module shipped with a skill) and binary files (e.g.
Word/.docx). Two independent failure modes, both silent (no error raised):
statsize/mtime) is served stale even when the data is current.How it shows up
triple-quoted string`; a second read returns the full file.
.docxarrives a few bytes short with a validPK\x03\x04header butzipfile.is_zipfile() == False, while the file is a valid zip on the host.read()returns the new content (hash changes) butstatsize and mtime stay unchanged.What we tried
outputs, uploads, .claude/skills) is fuse/virtiofs → host; only
/and/sessionsare VM-native ext4 (not a place to drop host files).
files correctly (#45433).
Easiest repro
Impact
Possible Relevant
Workaround
Adding a reproduction from a different workflow (NinjaTrader 8 / algorithmic trading scripts on Windows 11) that confirms the same root cause and adds a few technical details not in prior reports.
Setup: Cowork session mounted to C:\ClaudeCowork\Project\ on Windows 11. Scripts in that folder are also written to by NinjaTrader 8 (external process). Bash inside the sandbox confirmed the mount via /proc/mounts:
/proc/self/fd/3 on /sessions/.../mnt/Marketing Stratagy type fuse
(rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_other)
Symptoms matching this issue:
Cowork reads stale file content after NinjaTrader writes to the same file externally
stat inside the sandbox reports old size and mtime — metadata is stale, not just content
Persists across new sessions cold-started against the same folder
No error messages — Reads succeed silently with wrong data
Cowork edits built on a stale Read clobber content added in the interim (destructive partial overwrite)
Additional technical detail: The mount source is /proc/self/fd/3 — a file descriptor passed in at session start, indicating Cowork's FUSE server runs on the Windows side and the sandbox connects to it. The mount has no direct_io flag. Cache invalidation behavior appears to be controlled entirely by Cowork's FUSE server implementation, not by anything configurable from inside the sandbox.
Workaround in use: Read tool → Edit tool → Read tool to confirm (never bash cat/stat for verification). Works around the symptom but doesn't fix the underlying cache freeze.
Upvoting and watching. This is a correctness bug that silently corrupts work — a cache flush tool call or documented invalidation interval would help as a minimum mitigation.
partial work around (bad fix)
For existing files (editing in-place):
Read tool → Edit tool → Read tool to confirm. Never use bash cat, tail, or stat to verify — the sandbox mount is stale and will lie. Only the Read tool bypasses the cache.
For new scripts build from scratch:
Write/iterate in the sandbox's own temp space (/sessions/.../outputs/) where bash reads are fresh. Final Write tool call copies to the mounted folder. Avoids the stale mount entirely during development.
If a file looks corrupt after multiple edits:
Overwrite it whole with the Write tool rather than appending diffs — partial edits on a desynced file make it worse.
Never use bash for:
Verifying edits landed
Checking file size or mtime
Confirming content after a write
i added the partial work around to a process md file
@jaiello73-ops just curious: How did you manage never to use cat, tail, stat? Did you include special rules in your skill.md file to prevent claude from using those tools to validate file access? did you tell claude via Skill.md to always use Read and Write Tool?
Same root cause also corrupts the plugin install/update path (not just host-side / MCP edits),
silently breaking plugin skills/agents after an in-place re-upload.
Deterministic repro — Claude Desktop (Cowork), Windows 11, app 1.15962.1.0:
probe.pyis 136 bytes. In Cowork, read/execute it→
os.path.getsize()= 136 (correct).probe.pygrown to 39,772 bytes (on-disk content is the newversion — confirmed).
probe.py:os.path.getsize()and a full binary read both return136 (the old size); the returned bytes are the start of the new file cut off mid-line.
A brand-new file added in the same upload reads at full size — only the previously-cached,
now-grown file is clamped.
So a host-originated write via the plugin uploader leaves the virtiofs/bindfs size cache stale
exactly like the host-edit case here (and #42520, now closed as a dup of this). Full uninstall +
reinstall clears it; a plain re-upload doesn't. Originally filed as #72314 — closing that as a
duplicate of this one.
@hannes-hol, CLAUDE.md for the project — in the "Rules" section (bottom of the file). It states:
"Verify/read host files with the Read tool, never bash cat/tail — the sandbox mount serves stale or truncated content"
"If a file looks stale or truncated after multiple edits, overwrite it whole rather than appending diffs (Edit is fine for normal changes)"
"Always use the Read tool (not bash) to verify file changes, because the sandbox mount can serve stale or truncated content. If a file looks corrupted after edits, rewrite it whole instead of appending diffs" .... I know some of it is repeated .. after it happens I say write fix to md but never cleaned it
This issue has been opened for several months now. There are all of the reports and additional details on this bug, as well as the myriad of other bugs reports which got closed as duplicates. What gets this moved into a backlog to actually get fixed? The data corruption is bad, the data corruption when silent is bad, the truncation when you don't notice it and doesn't flag as corruption (e.g. a text file) is bad. Just concerned that its not getting seen with all of the automation against these bug reports.
Confirming this on Windows 11 + Claude Desktop Cowork, hit repeatedly since ~2026-06-10 across several sessions/projects on the same mounted folder. Wanted to share a more precise model of the bug plus a live repro, since "cache lag" undersells it — it's not a race, it's a per-session path-keyed cache that never invalidates, and it has a real data-corruption mode, not just staleness.
Refined model (each point separately measured, not inferred):
open(path, 'wb'), O_TRUNC) is write-through and repairs the view — verified via host-side SHA match. This is the only in-session repair we've found.O_APPEND,r+) against a stale view corrupts the host file mid-file. The append lands at the frozen EOF offset, not the real one, so new bytes get written into the middle of the real (larger) host file. Reproduced deliberately on a throwaway lab file — this is the mechanism behind several "randomly corrupted YAML/JSON" incidents we'd previously chalked up to something else.unlinkon the mount is denied (separately filed as #55206) — deletes need to happen host-side.**What we tried that did not help** (all tested dead, guest- and host-side):
O_DIRECT,statx(AT_STATX_FORCE_SYNC),posix_fadvise,drop_caches(no permission in the guest), fresh dentries / path case variants, 8.3 short names (disabled on the host volume),chmod,fsync/flock, host-sidetouch, rename-over, and delete+recreate. None invalidate the cached entry. Retry loops don't help either — a frozen view is stable and internally consistent (reported size matches bytes read), so there's no transient-error signal to retry against; it looks exactly like a normal, correct read.Practical impact: any workflow where a host process (an editor, a sync tool, another Cowork session, a scheduled task) writes a file that a long-running Cowork session has already touched will silently work from stale data for the rest of that session, and any append-style write from the guest back to that path risks corrupting the host copy.
We've since built a client-side mitigation (import-once-per-session / scratch-locally / export-whole-file, plus a guard that warns on the dangerous access patterns) since we can't wait on a fix, but obviously that's a workaround, not a fix for the daemon's cache invalidation. Happy to share our repro script/canary harness if useful — it's a ~5-line host+guest round trip that reliably demonstrates the frozen-length-with-new-bytes signature above and could probably be turned into a regression test for whatever fix lands here.
Some findings that narrow down where this bug lives, plus a workaround that recovers correct reads from inside the VM without restarting the session. Environment: Claude desktop Cowork on Windows 11, mounted folder on an NTFS drive, July 2026 build.
The cache is a per-path-spelling freeze of the size attribute, not stale data blocks.
Reproduced deterministically:
test.txt(184 bytes) in the mounted folder via Cowork's file tools; read it once in the sandbox (wc -c→ 184, correct).wc -c test.txt→ 184 (stale), andtailshows the new content truncated mid-line at byte 184.So the data blocks served are current — only the size attribute is frozen at whatever it was when that exact path spelling was first looked up. This explains both reported symptoms: truncation when a file grows, and NUL padding when it shrinks (reads past the real EOF up to the cached size return zeros). It also explains why the staleness is undetectable from inside:
stat,wc,md5sumall derive from the same frozen attribute.Evidence it's keyed by name spelling, and a workaround.
Windows resolves names case-insensitively, but the FUSE lookup path treats each spelling as distinct. Reading the same file through a never-before-used case variant of the basename returns the complete, correct file:
Additional properties, all reproduced multiple times in one session:
test.txtstill returns 184,TEST.TXTreturns 301, and a third spellingtESt.txtreturns the correct 340.DIR-VARIANT/file.txtreturns the same stale view as the plain path. The frozen attribute is associated with the final component's node, and a differently-cased parent lookup evidently resolves to the same cached child node.O_DIRECTreads, freshopen()from another process, and re-statall serve the stale view;drop_cachesis not permitted in the sandbox. Consistent with the OP: remounting doesn't help either, which suggests the frozen state lives on the host side (virtiofsd handle/attr cache keyed per name), not in the guest kernel.Practical workaround until this is fixed: read any possibly-modified file through a unique case-alias of its basename (a basename with n letters gives 2^n aliases). I've scripted this — walk a tree reading every file via an unused alias into
/tmp, then run whatever tooling against the fresh copies; ~250 files in ~0.6 s. Happy to share the script if useful.For the devs: the signature (size frozen at first LOOKUP per spelling; data blocks fresh; new spellings get fresh attributes; survives remount) points at an attribute/handle cache with effectively infinite TTL in the host-side virtiofs daemon's name-keyed lookup path, rather than the guest FUSE attr timeout. A Windows-side atomic-replace (temp file + rename, which editors and Cowork's own file tools appear to use) would give the file a new file ID while the daemon keeps serving the handle/attributes cached for that name.
Cross-refs: #41710 (silent truncation), #45433 (Cowork vs Claude Code tab divergence on same host), #55206 (unlink denied on the same mount).
Hit the same issue.
It's happening every day, corrupting my project.
Corroboration + a reliable in-session workaround + likely-related tickets.
We hit exactly this in an agentic workflow on Windows, where the same files are read/written both by native file tools (Win32
CreateFile/ReadFile) and by the Linux sandbox host-share mount (virtiofs). The signature matches yours precisely: after a host-side change, the sandbox keeps serving the old, truncated content — smallerwc -cthan the host, ending mid-word — with no error raised.Not OneDrive-specific: in addition to a case like your two machines, we reproduced the same stale/truncated view on a plain local NTFS path (
C:\, outside any cloud-sync layer), withstatreportingBlocks != 0at nonzeroSize— i.e. not a dehydrated cloud placeholder. So this is a host-share (virtiofs/Plan9) coherence bug, independent of the Windows Cloud Files API.The staleness is inode-bound, which yields a workaround (you noted remounting doesn't fix it — we saw the same): a
mvrename round-trip on the affected path (mv x y && mv y x) reliably refreshes the sandbox view, verified byte-identical (md5 before == after; length and trailing bytes restored). A freshly created file (new inode) also reads correctly. By contrast, a native file-tool full read does not reliably re-hydrate an already-cached inode, and starting a new session / remount does not reliably help — consistent with your report.Correlates with file size / very long lines; tiny files don't exhibit it (writes are seen immediately).
Same coherence root, write side: in-place bash writes (
sed -i, shell redirection>/>>) over a stale mount view can silently truncate files (data loss, no error) — we filed corroboration for that direction on #62140.Likely-related / same family: #50873, #41710, #42520, #45433 (FUSE cache-coherency / stale reads) and #62140 (write-side truncation, incl. the OneDrive Files-On-Demand variant). #38993 reads like the clean canonical statement of the read-side stale/truncation of the same underlying host-share coherence bug.
Ask: invalidate the mount-side cache on host
mtime/size change (or validate length/checksum against the host on open) so the sandbox never silently serves a stale inode; failing that, expose a supported "force re-coherence / clean remount" within a running session — amvround-trip should not be the only reliable lever.I can confirm the same issue has been happening for at least a few weeks in Cowork on Windows 11. This bug is NOT model specific as the bug states, it happens on any model and is unrelated to the AI's model.
Deleted the vm bundle and restarted, however the problem came right back.
Adding a data point I believe is new to this thread: a readdir / directory-listing miss on a directory with zero host-side modification. Most evidence in this cluster (#42520 / #45433 / #62932) is host-modify-then-guest-stale, which implicates the missing
fuse_lowlevel_notify_inval_*path. This case has no host mutation at all, so it points additionally at the readdir/lookup cache being wrong independent of invalidation.Environment (Cowork on Windows). Values below match the pattern reported across these issues; I have not re-pasted my exact mount line - confirm yours with
mount | grep sessions,uname -a,id:fuseover/mnt/.virtiofs-root/shared/..., options includedefault_permissions,allow_other, and noattr_timeout/entry_timeout/noac/auto_cacheWhat happened
lson the same absolute path, in the same session, resolved it instantly and completely. No host-side write, sync, rename, or delete had touched that directory - so this is not the "host modified the file, guest stayed stale" case.Downloads/missed 7 files that had just landed host-side.Readon a known path inside the "empty" directory returned correct content, consistent with the file tools bypassing the FUSE mount (matches #45433).Why it's worth a separate note. Case 1 looks like the same readdir-vs-lookup incoherence reported in #62932's Appendix B ("directory listings appear empty for files that exist"; the contradictory single-
ls), but reproduced on a cold, weeks-stable directory with no triggering host write. Implication: a host-to-guest invalidation fix alone would not fully cover it. It also argues for boundedentry_timeout/attr_timeout(ornoac, or disabling readdirplus caching) as defaults, so a cold or negative readdir result cannot persist unbounded.Smallest repro sketch (unchanged-dir variant, no host write involved):
Expected: both see the files. Observed: the agent readdir path returns empty while bash
lsis correct.Happy to capture an exact mount line / uid / probe transcript from a fresh session if useful.
Confirming #38993 on a third independent Windows machine, and adding four data points I don't see documented yet — a second corruption variant, a transient self-healing window, a frequency multiplier, and downstream git damage. Happy to provide logs/session IDs.
Environment
Cowork on Claude Desktop (Windows), local non-OneDrive folder on C:\...\Desktop\... (ruled OneDrive out explicitly — corruption persists without it).
Mount inside VM: fuse (fuseblk), rw,nosuid,nodev,relatime,default_permissions,allow_other, block size 4096.
Claude Code 2.1.197. Kernel 6.8.0-124 (Ubuntu 22.04). Model: Opus.
Repo is large (node_modules, datasets, dumps), which appears to widen the race window.
Data point 1 — a second corruption variant: NUL-padding (not just short truncation)
The original report describes files ending mid-word with a smaller byte count. I see that, and a distinct second variant: the file is padded out to (or near) its full expected length with \x00 bytes at the tail — dozens to thousands of NULs (observed counts: 74, 229, once 11,127). wc -c reads full size, but the tail is zeros.
Inference (flagged as inference): this looks like sparse-file behavior — the metadata length is set correctly but the final data pages aren't flushed across the mount, so the unwritten tail reads back as zeros. That's a different signature from the mid-word truncation and may point at a separate flush/ordering path. Worth treating as two manifestations of the same underlying race.
Data point 2 — a transient, self-healing race window (distinct from persistent stale cache)
The original notes "remount doesn't fix it" (persistent staleness). I also see a transient mode that resolves on its own: a file read immediately after a VM-side write shows a truncated tail and fails to parse, but re-reading the same file a second later shows it complete and valid — no remount, no rewrite. Reproducible pattern: catch a write mid-flight → truncated snapshot; the flush lands a beat later → file is whole.
Practical implication for triage: a single "is this file corrupt?" check produces false positives. The reliable test is read → detect → re-read once; if it heals, it was a mid-write race, if not, it's the persistent stale-cache case.
Data point 3 — concurrent host-side writer massively increases frequency
Corruption frequency jumped from "rare" to "most sessions" after I began keeping a VS Code-family IDE (Antigravity) open on the same folder — even as a passive explorer. IDE buffer write-back, format-on-save, and the file watcher act as a second host-side writer racing the mount. Closing all editor tabs (and disabling auto-save / format-on-save) drops the frequency sharply. This suggests the bug is a genuine read/write race at the mount boundary, and any additional host-side writer is a strong aggravator — useful both as a mitigation to document and as a reliable way to increase repro rate for debugging.
Data point 4 — downstream damage to git metadata
When an interrupted write hits git's own files, it leaves a stale 0-byte .git/index.lock (and submodule index.locks). No git process is holding it, but GitHub Desktop / git commit then fail with a file-lock error until it's manually deleted. So the mount race isn't limited to source files — it corrupts VCS metadata and blocks commits, which is how it first became visible to me.
Detection snippet (for repro / CI-style checks)
bash# NUL scan + tail check
for F in path/to/file.tsx; do
echo "$F NULs=$(tr -cd '\000' < "$F" | wc -c) lastbyte=$(tail -c1 "$F" | xxd -p)"
done
js// parse-validity check (TS/TSX)
const ts = require('typescript'), fs = require('fs');
const src = fs.readFileSync(f, 'utf8');
const sf = ts.createSourceFile(f, src, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
console.log(f, sf.parseDiagnostics.length === 0 ? 'OK' : 'DIAG', '| NULs=' + (src.match(/\x00/g)||[]).length);
Suggested repro to raise the hit rate
Mount a large folder; open it in a VS Code-family IDE with auto-save + format-on-save on.
Have Cowork write/edit several files in a loop while the IDE watches.
After each VM write, wc -c + NUL scan + parse. Expect both variants (short tail and NUL-padded), plus occasional transient hits that heal on re-read.
Glad to share full session IDs and before/after byte dumps if that helps narrow the flush path.
Additional data point (July 2026) — confirms this is still open, adds binary-file + forensic detail
Reproduced independently on a different setup, several months after the original report, so this is not a regression that got fixed and came back — it appears to have never been fixed.
Setup: Claude Desktop, Cowork (research preview), Windows, workspace folder is a plain local drive (no OneDrive, no cloud sync of any kind).
What's new here compared to the original report:
Affects binary/compound files, not just plain text. The original report used a text file; I reproduced the same class of bug on a .docx (OOXML zip container, ~468 KB).
Forensic detail on the truncation: after an external edit (Microsoft Word, save + close) and re-read via bash inside the same Cowork session:
MD5 hash of the mount-served file did change vs. the pre-edit version (so it's not a 100%-frozen snapshot; some new bytes arrived).
File size stayed byte-identical to the pre-edit version (unexpected — the edit removed text).
Manual zip structure check: valid local file header (PK\x03\x04); local file headers present (27 found via regex scan); central directory headers (PK\x01\x02) count = 0; End-Of-Central-Directory (PK\x05\x06) absent. The file is truncated exactly where the real central directory/trailer should begin — consistent with what's described here as "content ends mid-word," just for a binary container instead of text.
Confirms "remount doesn't fix it," and additionally: it's not a timing issue either. I re-requested the workspace folder connection (request_cowork_directory) against the same path after the stale read — identical hash, identical truncation. I then waited ~35 seconds and read again — still identical. So this isn't propagation lag; the cache is not being invalidated by anything short of what's described in #69866 (full quit + relaunch of the desktop app).
Per-file, not whole-mount: in the same session, a second, previously untouched filename in the same folder read correctly at the same moment — matching the per-inode staleness described in #45433. Worth noting since it means simple whole-mount health checks won't catch this.
Given the overlap with #45433, #40264, #41710, #40191, #62140, #69866 (all pointing at the same virtiofs/FUSE mount-cache layer, just triggered by different host actions — OneDrive Files-On-Demand, Excel, Word, plain text editors), it might be worth consolidating around this issue as the root-cause tracker, since it already correctly identifies the mount layer (/mnt/.virtiofs-root/shared/, FUSE) rather than the many app-specific symptoms.
Suggested fixes (unchanged from the mount-layer diagnosis): invalidate the FUSE attribute/content cache on host file change (inotify/USN journal on the Windows host side feeding the virtiofs daemon), validate length/checksum at the mount bridge before serving reads, and expose an explicit resync/drop-cache affordance that doesn't require a full app relaunch.
Fable tells me this can be suseful:
Repro report (Cowork, Windows, non-OneDrive local folder)
Related: #45433, #41710, #38993 (virtiofs→FUSE stale reads), #51214 (Write/Edit silent flush), #67585 (reproduced under Fable 5).*
Summary
On Cowork (Claude desktop) with a Windows host and a local, non-OneDrive folder (
D:\Projects\...), the sandbox mount both (a) serves stale/truncated reads of files the host wrote correctly, and (b) loses writes made by agent-teams subagents at teardown — they never reach the durable store, so a later fresh session reads them as absent. In-session verification is fooled because it reads the same stale view, so a data-loss event can pass a "clean" check and only surface in a later session. Many occurrences across the last three weeks.Environment
D:drive (not OneDrive, not a network share).Observed behavior (four independent instances in one session)
Read-side — stale size cache clips a grown file.
A Python script edited (via the Write tool) from ~16 KB to ~17.9 KB read back through the sandbox as exactly 17366 bytes, truncated mid-line — enough to cause
SyntaxError: unterminated string literalunderpython3 -m py_compile. The host-native read tool showed the full, correct file.sync; sleep 6did not refresh the view; the cached old size persisted. Writing the same content to a brand-new path (fresh inode, no cached size) read back correctly — consistent with "FUSE refreshes data pages but never invalidates cached file size."Read-side — truncated markdown.
A 136-line markdown file read via sandbox
tail/wc -las 75 lines, ending mid-sentence; the host-native read showed all 136 lines intact.Read-side — phantom absence.
cat circles/<file>.jsonin the sandbox returned "No such file or directory" for a file that existed on the host and was readable via the file tool moments earlier.Write-side — total loss of subagent writes at teardown (the costly one).
At the close of one session, six subagents each wrote a small markdown record and were then stood down. An in-session presence check passed (the files read as present through the sandbox view). A fresh scheduled session hours later found all six absent — host-side mtimes confirm only later, manually reconstructed copies exist; the originals never landed. Files the lead/host wrote at the same moment (a transcript and a JSON manifest) persisted fine. The pattern — all six lost together, lead writes fine, in-session check fooled — points to subagent writes landing in a session-layer view that isn't flushed to the durable store before teardown, rather than six independent message drops.
Impact
Silent data loss with false-clean verification: any in-session integrity check reads the same unreliable view, so "it's present / it saved" cannot be trusted across a session boundary. Downstream automation that reads the files in a later session sees absence and treats it as "no data," with no error raised.
Minimal reproduction (suggested)
On a Windows Cowork session with a local non-OneDrive folder:
wc -c,tail) → observe the read clipped to the old byte size, truncated mid-content. A new file path reads correctly.What would help
I use your workaround in Claude instructions to automatically apply the name variant every time Claude reads the file (with a counter for each file). This makes the bug transparently to users (in Windows environment). For example, for a file name containing 29 characters, we have up to 2²⁹ - 1 aliases to use, which should prevent the bug from ever being encountered.