[BUG] Cowork: virtiofs FUSE mount serves truncated/stale files — host-side file changes not reflected in VM

Open 💬 45 comments Opened Mar 25, 2026 by eawagu

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)

View original on GitHub ↗

45 Comments

github-actions[bot] · 3 months ago

Found 1 possible duplicate issue:

  1. https://github.com/anthropics/claude-code/issues/28890

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

brenny1102 · 3 months ago

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.

enktech · 3 months ago

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

  • OS: Windows (latest updates)
  • Claude Desktop: Latest as of 2026-03-31
  • Source path: S:\Projects\1AM_Brushless_Motors (secondary/shared drive)
  • Mount point: /sessions/<session-id>/mnt/1AM_Brushless_Motors

Reproduction

  1. Selected S:\Projects\1AM_Brushless_Motors as Cowork workspace — folder contains .md files
  2. All access methods from within the sandbox return empty:
  • ls -la → shows only . and ..
  • find / -name "PKA_Agent_Methodology.md" → no results
  • Glob tool → "No files found"
  • File upload via chat attachment → metadata arrives, file content does not
  1. Writing to the mount has not been tested yet (can't get past reading)

Additional 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 .md files (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.

kaseylcade · 3 months ago

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.

menezesclayton · 3 months ago

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

can-finance · 3 months ago

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 -l reports 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 \x00 bytes. json.JSONDecodeError: Extra data fires 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 and file reports a valid format, but zipfile.is_zipfile() returns False and openpyxl raises BadZipFile. 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.

nbroderick-code · 3 months ago

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.

can-finance · 3 months ago

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

aphasiamiu · 3 months ago

Additional data points confirmed on Windows 11 desktop app:

  1. posix_fadvise(POSIX_FADV_DONTNEED) does not help. Returns 0 (success) but subsequent reads still return stale content. This is consistent with brenny1102's finding that drop_caches also fails — both only affect the Linux kernel page cache, which is upstream of where the stale data actually lives (the FUSE userspace daemon's own cache).
  2. /proc/mounts shows concurrent bindfs mounts for the same user folder across different sessions. This suggests the underlying FUSE daemon is shared across session boundaries, which would explain why starting a new session (new VM instance) does not clear the cache — the daemon (and its stale metadata) persists independently of the VM lifecycle.
jusmar · 2 months ago

---

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

  1. Bug is bidirectional. This thread documents host → guest stale reads (and #42520 named the stack). I also see guest → host silent truncation on small-file writes through the same bindfs layer — the Edit/Write tools report success, Read returns the intended content, bash cat on the same path shows a truncated reality.
  2. Git is structurally broken in Cowork sandboxes on Windows. git init produces a 54-byte all-NUL .git/config and skips .git/objects/info|pack/ creation. .git/index independently NUL-pads during normal commit operations. Neither outcome is in the current thread.
  3. **Cache lag is measured in days of mtime, not seconds. Directly observed: a host-side write to a file on /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.
  4. The workaround proposed in #42520 ("use Read/Edit/Write instead of MCP tools for file writes") is necessary but not sufficient for this failure class. Those are the exact tools that silently truncate my files. This comment's own draft file hit the bug three times in a row while being written — Edit silently dropped the new content, Write silently dropped it again, and only cat > file <<'EOF' … EOF from bash finally landed cleanly.
  5. Upstream-documented remediation that would eliminate the symptom class: virtiofsd --cache=none, versus the current auto default (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 mount inside the sandbox) | bindfs on /sessions/<id>/mnt/skills type fuse.bindfs on top of /mnt/.virtiofs-root/shared/…; direct virtiofs-fuse on /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). Bash cat on the same path shows the truncated reality. On bindfs, bash is authoritative — the file on disk really is truncated, and a downstream git add will 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 by wc -c and grep on the intended new section header.

<details>
<summary>Minimal reproduction (click to expand)</summary>

# Inside a Cowork sandbox session with a D:-drive workspace mounted
SAMPLE=/sessions/<session-id>/mnt/<folder>/sample.json
echo '{"keywords":["a","b","c","d","e","f","g","h"]}' > "$SAMPLE"

# Via the session agent's Edit tool, replace "d" → "dddddddddd" in $SAMPLE
# Tool reports success; Read shows intended content; then verify via bash:
wc -c "$SAMPLE"                 # may report shorter than expected
tail -c 40 "$SAMPLE"            # may end mid-token
python3 -c "import json; json.load(open('$SAMPLE'))"
# → json.decoder.JSONDecodeError: Unterminated string

</details>

2. git init produces a 54-byte all-NUL .git/config, and skips object-dir creation

Running git init in a fresh directory on a bindfs mount:

  • .git/config is 54 bytes of \x00 with no text content.
  • .git/objects/info/ and .git/objects/pack/ are missing entirely.
  • Subsequent git add/git commit fail.

<details>
<summary>Minimal reproduction</summary>

cd /sessions/<session-id>/mnt/<folder>/
mkdir test-init && cd test-init
git init
xxd -c 16 .git/config | head                # all 00 bytes
ls .git/objects/                            # missing info/ and pack/

Recovery requires heredoc-rewriting .git/config to a valid core block and mkdir -p .git/objects/info .git/objects/pack. Running the same git init on the same D: drive outside Cowork (Claude Code, Git Bash, PowerShell — all tried) produces a valid 112-byte text .git/config and the expected object dirs.
</details>

3. .git/index NUL-padding during commit preparation

Independent of init — on a long-running repo, certain git update-index/commit paths that do an atomic-rename write to .git/index can produce an index file that is entirely NUL bytes (no DIRC magic signature). Observed concretely: a 40,424-byte all-NUL .git/index after a git update-index --cacheinfo. Every subsequent git command fails with error: bad signature 0x00000000 / fatal: index file corrupt.

Recovery: mv .git/index .git/index.corrupted.<tag> (unlink is denied on bindfs — rename is the workaround), then git read-tree HEAD to rebuild the index from the last commit. Verify the new index begins with the DIRC magic (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 the git init attempt.

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. git subprocesses write .git/index and 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 via git -c user.name=… -c user.email=…) and then hand the git push back 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 via wc -c + parser round-trip before git add is 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 --cache flag directly governs this behaviour:

--cache=none|auto|always — "none forbids the FUSE client from caching to achieve best coherency at the cost of performance. auto acts similar to NFS with a 1 second metadata cache timeout. always sets a long cache lifetime at the expense of coherency. The default is auto."

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=none would 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 → sandbox on 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

  1. Triage acknowledgement on #38993. The thread has sat for 27 days with 9 👍, 7 closed duplicates, and multiple independent-user repros, with no MEMBER/COLLABORATOR/OWNER response. A "received, reproducing, investigating" note would let affected users plan around the issue.
  2. Confirm or refute the --cache=auto default 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.
  3. Clarify the Windows-vs-macOS architectural divergence — specifically whether the bindfs layer is Windows-host-only.
  4. Consider a "reliability mode" session toggle trading throughput for coherency (--cache=none + any analogous bindfs adjustment).

Happy to provide additional diagnostics on request: full mount output, raw strace of 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.

MBHansen · 2 months ago

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.

jusmar · 2 months ago

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.

iamGTB · 2 months ago

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:

  1. Cowork Edit tool appended ~3 KB of content to a tracked .md file in a host-mounted folder. Edit tool returned success.
  2. Post-edit bash verification (wc -l, stat, tail, grep -c, md5sum) all reported the file unchanged at the pre-edit size and md5.
  3. Read tool against the same file showed the new content present (full appended block visible).
  4. Tried touch + sync + sleep 2. Bash view partially updated and showed the file ending mid-sentence -- I initially misdiagnosed this as a partial write / truncation.
  5. Bash echo "..." >> file reported exit 0 but grep -c for the appended marker returned 0 -- bash could not see its own write either.
  6. Ran mv file.md file-c.md + sync + sleep 2.
  7. Post-rename: the file's true size and content surfaced. Both the Edit write AND the bash sentinel append from step 5 were present in full. The Edit had never been partial; bash's read paths were the only thing lying.

Two specifics that add to the original report:

  • Bash diagnostics (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.
  • Bash WRITES land on disk; only bash READS serve stale content. The cache appears to be on the read path, not the write path.

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.

can-finance · 2 months ago

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.

jusmar · 2 months ago

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 👀👀👀

kshirai-studioz · 2 months ago

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

  • OS: Windows (MSIX install)
  • Claude Code version: 2.1.110
  • Model: Opus 4.6
  • Mount type: virtiofs → FUSE (/mnt/.virtiofs-root/shared/c/claude/sessions/.../mnt/claude)
  • Mount options: rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_other
  • No entry_timeout, attr_timeout, or negative_timeout specified (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 file returns the correct latest content after remount
  • stat file returns stale size, mtime, and ctime from a previous state
  • ls -la shows stale metadata

This 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 stat returns stale metadata (wrong size, wrong mtime) while cat returns 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 differences
  • rsync — uses mtime + size to detect changes; will miss host-side modifications entirely
  • make and build tools — rely on mtime to determine what needs rebuilding
  • find -newer — returns wrong results because mtime is frozen
  • git status / git diff — stat-based change detection fails; git may not see that files have changed on disk
  • ls -lt (sort by time) — shows wrong ordering

This 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_timeout or attr_timeout is set, which means the kernel caches indefinitely. Setting these to 0 (or a short TTL like a few seconds) would fix both the content and metadata staleness:

-o entry_timeout=0,attr_timeout=0,negative_timeout=0

Alternatively, the remount operation should ensure both page cache and attr cache are invalidated.

dbachen-dt · 2 months ago

_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.

.docx files show a specific corruption pattern

When the host modifies a Word .docx file in the mounted folder, the bash-visible version of that file:

  • Starts with a valid ZIP local-file-header signature (PK\x03\x04) and contains all 27 expected docx parts as local file header + compressed data records
  • Is missing the End-of-Central-Directory record (the PK\x05\x06 trailer); the tail of the file is zero-padded
  • python-docx fails to open with PackageNotFoundError
  • zipfile.is_zipfile() returns False
  • zip -FF source.docx --out recovered.docx successfully reconstructs the central directory from the surviving local file headers; the recovered file opens cleanly in python-docx

The 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:

  • Initial bash-visible mtime: 2026-05-10 19:05:14 UTC
  • Host-side last-save mtime per Windows (confirmed by user): 2026-05-10 22:21 UTC (3h 16m later)
  • Multiple bash re-reads across the gap: mtime unchanged at 19:05:14 UTC every time

This exceeds the cache_duration_s = 3600 figure 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 cp from a stub file would always produce the fully-hydrated content. We tested this directly: cp from 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

  • #55877 — identifies cache_duration_s = 3600 in 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 all
  • #45125 — proposes launching virtiofsd with cache=none on workspace mounts as the fix

Happy to provide further diagnostic data (additional stat outputs, hex dumps, the zip -FF recovery procedure that consistently worked, etc.) if it helps. The Cowork session transcript captured a complete diagnostic trail.

tisalvadores · 2 months ago

_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, fresh open(), 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.

AcId9381 · 2 months ago

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 -c reporting 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 holds st_size (and mtime, and mode) from the last sandbox-originated operation, and cat reads 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 -m is 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, and stat doesn'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 X is 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 chain bash-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 git operations on Windows (.git/index is the canonical case), (d) trust the file tool's view over cat / stat whenever 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.

vlado10076-spec · 1 month ago

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:

  • First read of a NEW path (mount has never seen): fresh fetch from Windows ✅
  • All subsequent reads of that path: serve from cache. Content cache updates partially from Windows-side changes but size/mtime cache stays frozen at first-read values.
  • Result: when underlying file grows beyond cached size, mount returns truncated bytes → BadZipFile for .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.move back to original path | ✅ Original path cache refreshed |
| Sandbox open(p,'wb').write() (own write) | ✅ Write-through, full cache update |
| os.remove from sandbox | ❌ PermissionError — blocked |

Triple-confirmed truncation pattern

Same pattern reproduced on three different .xlsm files (БМ, 01, 001) in same session:

  • Pre-edit: size N₀, valid ZIP
  • After Excel save: size N₀ (frozen!), md5 different (content cache updated), BadZipFile (EOCD truncated at byte N₀ when real file is N₀+25)

Working workaround (sandbox-only, no user upload needed)

import shutil, time, os, uuid

def refresh_mount_cache(file_path: str) -> None:
    """Sandbox move-out + move-back forces fresh read."""
    folder = os.path.dirname(file_path)
    name, ext = os.path.splitext(os.path.basename(file_path))
    stamp = f"{time.strftime('%y%m%d%H%M%S')}_{os.getpid()}_{uuid.uuid4().hex[:6]}"
    temp_dir = os.path.join(folder, "Temp")
    os.makedirs(temp_dir, exist_ok=True)
    temp = os.path.join(temp_dir, f"{name}_refresh_{stamp}{ext}")
    shutil.move(file_path, temp)
    shutil.move(temp, file_path)

Verified end-to-end on real master .xlsm files (ИБ.xlsm: 704,035b stale → 826,747b fresh after refresh).

Suggested fix priorities

  1. Invalidate size cache on file-open when Windows file size differs from cached (cheapest, narrowest patch — would solve the majority of cases)
  2. Or NFS-style close-to-open consistency (check mtime on every open)
  3. At minimum: surface stale warning to agents when cached size ≠ underlying size, so silent corruption becomes detectable

Why this matters

For ZIP-based formats, BadZipFile is 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.

mstenback · 1 month ago

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 / tail in bash:

  • Two silent failure modes. (a) Truncated write: file is written but cut

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.

  • Retrying the identical Edit doesn't help. One file: ran the same Edit

twice, both reported success, file unchanged (61966 bytes) both times. It
applied only after switching to a bash/Python write.

  • bash/Python writes to the same mount were reliable. In the same session,

~14 writes via cat >> heredoc and Python open().write() had zero
failures. The fault tracks the Edit/Write tool path — not a globally broken
mount.

  • Loss can be far from the edit site. A ~770-line file edited only at the

top was left with its final paragraph truncated. This suggests the
whole-file rewrite is what gets truncated, not the edited span.

  • Frequency is high — roughly 9 of ~15 substantive Edit/Write calls in one

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.

yurukusa · 1 month ago

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, stat size/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-branch shrinking .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:

  • Matches Bash tool calls with a working dir or git -C <path> argument inside /sessions/<id>/mnt/
  • Fires only on the dangerous subcommands (status, add, commit, diff, restore, stash, checkout -- <path>, clean, ls-files)
  • Stays silent on the safe ref-only subcommands (rev-parse, log, show, cat-file)
  • Always exit 0 (advisory only); env vars to silence (CC_COWORK_FUSE_QUIET=1) and log (CC_COWORK_FUSE_LOG=…)
  • Walks through the recovery procedure when .git/config itself has been corrupted by the NUL-padded shrink (rewrite via cat > .git/config inside 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 commit over 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.

ddimitrov-0 · 1 month ago

Workaround: ZIP comment padding

TL;DR: Pad your openpyxl-saved .xlsx files 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 openpyxl save, 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.

import struct

def apply_zip_padding(path, target_kb=60):
    with open(path, 'rb') as f:
        data = f.read()
    eocd_offset = data.rfind(b'PK\x05\x06')
    if eocd_offset == -1:
        return  # not a valid ZIP, skip
    pad_size = min(65535, target_kb * 1024 - len(data))
    if pad_size <= 0:
        return  # already large enough
    eocd = data[eocd_offset:eocd_offset + 22]
    new_eocd = eocd[:20] + struct.pack('<H', pad_size)
    padded = data[:eocd_offset] + new_eocd + data[eocd_offset + 22:] + b'\x00' * pad_size
    with open(path, 'wb') as f:
        f.write(padded)

Call apply_zip_padding(path) after every wb.save(path).

Caveats

  • ZIP comment max is 65535 bytes, so the padding ceiling is ~64KB above your base file size. For typical openpyxl-generated files (~10–15KB) this gives ~50KB of headroom — enough for normal Excel saves.
  • If the user's Excel save ever exceeds the padded size, you're back to truncation. Increase target_kb if needed.
  • The padding bytes are null (\x00). Excel ignores the ZIP comment entirely and will strip it on save, which is fine — the next VM write re-applies it.
  • Tested on Cowork desktop (Windows), Claude Code 2.1.78, openpyxl 3.1.x.

Hope this helps while a proper fix lands.

sk-j-hiros · 1 month ago

Additional reproduction data from a long-running production session (2026-06-04, Cowork sandbox).

Environment

  • Cowork sandbox VM mounting a real production git repository via FUSE daemon
  • Host: Windows / Claude Desktop with Cowork
  • Linux side uid=1059 (non-root), virtiofs kernel module not loaded; pure FUSE daemon
  • mount options: rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_other (no cache-related options)

Observed symptoms

  • stat <file> returns successful inode/size/mtime
  • [ -f <file> ] test returns true
  • ls -la <file> outputs BOTH "No such file or directory" AND the file entry in the same command
  • dd if=<file> bs=1 count=10 fails with "No such file or directory"
  • git config --list fails with fatal: error processing config file(s)
  • git checkout -b <branch> fails with fatal: unknown error occurred while reading the configuration files

Workarounds tested

  • Folder disconnect/reconnect via Cowork UI: initially effective but stopped working after a long session
  • No way for sandbox-side process to detect the staleness from inside (stat succeeds while read fails)

Operational impact

  • All git operations had to be delegated to host PowerShell
  • Sandbox usable only for file edit and bash text processing

Workaround in our internal regulation

  • Mandated all git operations via host PowerShell when sandbox git config --list fails
  • Auto-detection guard git config --list || exit 1 injected at top of all relevant scripts

Note: closed-as-duplicate #45433 reports the same root cause but has no linked parent issue. Subscribing here for updates.

dmynguy-hub · 1 month ago

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 -c in bash because "the Read tool returns the in-memory buffer and lies." This test inverts both claims. The write path is correct; the bash wc -c reads 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_other and no cache-bounding options; once a path's st_size is cached from the last sandbox-originated operation, every later read clamps at that size. cat reads 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:

  • Keyed by path/dentry, not inode or content: copy to a new name reads full, rename back serves stale (brenny1102; vlado10076-spec's 18-test matrix).
  • Cleared only by a dentry rebuild: mv X X.tmp && mv X.tmp X is the one unprivileged escape (AcId9381). touch -m is absorbed without reaching the daemon.
  • Survives everything coarser: drop_caches and connections/N/abort are 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

  1. Fail loud now (harness-level, ship independently). The desktop app already holds the authoritative post-write size from its own bridge. Compare it to the sandbox stat and 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).
  2. Close-to-open consistency on writable shares. Serve writable mounts with attr_timeout=0,entry_timeout=0 on the bindfs re-export and revalidate-on-open at the virtio-fs layer (--cache=auto/never, not always; 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.
  3. Active invalidation (keeps the cache, restores correctness). Watch the shared directories host-side (ReadDirectoryChangesW) and forward change events into the guest as FUSE notify / virtio-fs notifications to drop cached attrs and pages on the affected path.
  4. Make the verification channel trustworthy. Document that, post-write, the Read tool reflects disk and bash stat/wc -c may 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 outputs mount, 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 stale attr_valid is an Anthropic-side check with daemon logs or root in the guest.

AndrewLaganaro · 1 month ago

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

Plexcalibur · 27 days ago

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 -c shows the pre-edit size, the inode is
unchanged, and sync, waiting several seconds, and remounting all fail to
refresh 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.

acmeaom · 22 days ago

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.

hannes-hol · 21 days ago

Confirming...

Environment

  • OS: Windows 11 Pro, 10.0.26200
  • Claude Desktop / Cowork: Version 1.15200.0 (250bae)
  • Mount: virtiofs → FUSE at /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):

  • Data is served stale/truncated.
  • Metadata (stat size/mtime) is served stale even when the data is current.

How it shows up

  • A skill's Python file is read truncated mid-file → `SyntaxError: unterminated

triple-quoted string`; a second read returns the full file.

  • A .docx arrives a few bytes short with a valid PK\x03\x04 header but

zipfile.is_zipfile() == False, while the file is a valid zip on the host.

  • After an in-place host edit, read() returns the new content (hash changes) but

stat size and mtime stay unchanged.

What we tried

  • New Cowork task → no effect (same long-lived VM, see below).
  • Staging files into the Cowork work dir → no effect: every user-reachable mount (tmp,

outputs, uploads, .claude/skills) is fuse/virtiofs → host; only / and /sessions
are VM-native ext4 (not a place to drop host files).

  • Ruled out OneDrive hydration — the file is complete on the host.
  • Only reliable workaround: run the same skill in Claude Code, which reads the same

files correctly (#45433).

Easiest repro

Host (PowerShell), in the Cowork-Work-Folder:
powershell
Set-Content .\repro.txt -Value ("A"*1000) -NoNewline -Encoding ascii

Cowork (bash):
sha256sum repro.txt; stat -c 'size=%s mtime=%y' repro.txt

Host — overwrite in place, same length, different content:
Set-Content .\repro.txt -Value ("B"*1000) -NoNewline -Encoding ascii

Cowork (bash), same task:
sha256sum repro.txt; stat -c 'size=%s mtime=%y' repro.txt

→ SHA-256 changes, but size + mtime stay stale.

Impact

  • Silently wrong results in correctness-critical file IO.
  • Inflated runtime and token usage: when a read comes back truncated/corrupt, the agent retries, invents theories about the cause, and improvises workarounds instead of failing fast — burning tokens and wall-clock time.
  • Blocks / delays a production document-generation workflow on Windows.

Possible Relevant

  • A "new task" reuses the same VM: identical boot_id, continuous uptime (~8h), and a /tmp marker survives across tasks → the cache is never invalidated by starting a new task; only a full app/VM restart would.
  • Data cache and attribute cache invalidate independently.

Workaround

  • Use Claude Code. There file access works as expected
jaiello73-ops · 19 days ago

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

hannes-hol · 17 days ago

@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?

Caffarelli · 17 days ago

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:

  1. Install a plugin from a .zip where script probe.py is 136 bytes. In Cowork, read/execute it

os.path.getsize() = 136 (correct).

  1. Re-upload the same plugin with probe.py grown to 39,772 bytes (on-disk content is the new

version — confirmed).

  1. New Cowork session, read probe.py: os.path.getsize() and a full binary read both return

136 (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.

jaiello73-ops · 16 days ago

@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

dbachen-dt · 15 days ago

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.

marcallman · 14 days ago

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):

  • First observation of a path is fresh. The first time the guest reads/stats a given path in a session, it's correct. New files created host-side after mount also show up fine in directory listings.
  • Once observed, the path is frozen for the rest of the session — indefinitely, not a brief window. Host-side rewrites after that first observation are invisible. Critically, reads don't error or return the old content byte-for-byte — they return the new bytes truncated to the old length. Example from a canary test just now: host rewrote a 1024-byte file to 4096 bytes of a different byte value; the guest's re-read still reported a 1024-byte file, but the content was the new byte value — i.e., new data, wrong length. stat/mtime are frozen too.
  • A guest whole-file rewrite (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.
  • A guest append or positioned write (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.
  • Remounting does not clear it (confirms what's already noted in this issue and #45433).
  • A brand-new session starts with an empty cache — the state dies with the session/daemon.
  • Guest unlink on the mount is denied (separately filed as #55206) — deletes need to happen host-side.
  • Host-side tools that operate outside the virtiofs/FUSE path (e.g. native Windows file APIs) always see the true current state, as expected.

**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-side touch, 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.

Fuuj0r · 14 days ago

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:

  1. Create test.txt (184 bytes) in the mounted folder via Cowork's file tools; read it once in the sandbox (wc -c → 184, correct).
  2. Edit the file via file tools so it grows to 301 bytes.
  3. In the sandbox: wc -c test.txt184 (stale), and tail shows 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, md5sum all 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:

$ wc -c test.txt        # 184  — stale (spelling used before the edit)
$ wc -c TEST.TXT        # 301  — correct, full content

Additional properties, all reproduced multiple times in one session:

  • Each alias freezes at its own first lookup: after a further edit (→340 bytes), test.txt still returns 184, TEST.TXT returns 301, and a third spelling tESt.txt returns the correct 340.
  • Case-varying a parent directory does not refresh children — DIR-VARIANT/file.txt returns 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_DIRECT reads, fresh open() from another process, and re-stat all serve the stale view; drop_caches is 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.
  • Writes VM→host propagate correctly (confirming the one-way observation above).

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).

SteffenEnz · 13 days ago

Hit the same issue.

shyoo · 13 days ago

It's happening every day, corrupting my project.

rstribrn · 12 days ago

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 — smaller wc -c than 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), with stat reporting Blocks != 0 at nonzero Size — 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 mv rename 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 — a mv round-trip should not be the only reliable lever.

phoem · 7 days ago

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.

mxssmu · 7 days ago

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:

  • mount type fuse over /mnt/.virtiofs-root/shared/..., options include default_permissions,allow_other, and no attr_timeout / entry_timeout / noac / auto_cache
  • guest Ubuntu 22.04, kernel 6.8, non-root uid

What happened

  1. Unchanged-directory readdir miss. A subfolder in my mounted working tree (~127 files, all mtimes 3-6 weeks old, nothing written to it in over a month) returned empty from the agent's Glob / directory-walk tool. A plain bash ls on 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.
  2. Fresh-arrival miss (the more familiar mode). In the same session, a start-of-session walk of Downloads/ missed 7 files that had just landed host-side.
  3. Harness Read on 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 bounded entry_timeout / attr_timeout (or noac, 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):

# guest bash, fresh session, on a mounted dir NOT touched host-side in weeks:
<agent Glob/readdir tool>  ProjectDir/StableSubdir/**   -> returns nothing
ls -la ProjectDir/StableSubdir/                          -> lists all N files, same session

Expected: both see the files. Observed: the agent readdir path returns empty while bash ls is correct.

Happy to capture an exact mount line / uid / probe transcript from a fresh session if useful.

AICoevolution · 7 days ago

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.

Doubleb85 · 7 days ago

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.

DavidCheney · 4 days ago

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

  • Cowork / Claude desktop, Windows host, project folder on a local D: drive (not OneDrive, not a network share).
  • Work is done both through the host-native file tools (Read/Write/Edit) and the Linux VM sandbox (bash), which sees the folder via the virtiofs→FUSE mount chain.
  • Heavy use of agent-teams: ~7 persistent subagents spawned per \session each writing a small markdown file at close, then torn down.

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 literal under python3 -m py_compile. The host-native read tool showed the full, correct file. sync; sleep 6 did 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 -l as 75 lines, ending mid-sentence; the host-native read showed all 136 lines intact.

Read-side — phantom absence.
cat circles/<file>.json in 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:

  1. Stale size: grow an existing file via the Write tool (add several KB), then read it from the bash sandbox (wc -c, tail) → observe the read clipped to the old byte size, truncated mid-content. A new file path reads correctly.
  2. Subagent write loss: have a subagent write a file immediately before it is torn down; from a fresh session, read the path → observe absence, while a lead/host-written file from the same moment persists.

What would help

  • Invalidate the FUSE attribute (size) cache on the underlying host change, not only data pages.
  • Ensure subagent/host writes are flushed to the durable store before teardown (or surface an error if they cannot be).
  • Until then, a durable, out-of-band verification path (host-native re-read + checksums, reconciled from a separate process) is the only reliable way to confirm a write survived — which is the mitigation we've had to build on our side.
paxsonyang · 2 days ago
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.

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.