[Bug] virtiofs mount serves truncated file contents to sandboxed environment while host files are clean

Status Closed — duplicate
Reported on v2.1.110
Maintainer reply None cached
Activity 9 comments · opened Apr 19, 2026 · closed Aug 19, 2026

Bug Description
Summary: Cowork's virtiofs mount served stale/truncated file contents to the sandboxed Linux environment while the host Windows disk was clean. Git-level tools inside the sandbox reported the working tree as modified, files ended mid-statement, and python -m py_compile raised SyntaxError — all on files that were verified clean and matching HEAD from the host's PowerShell.
Repro:

On Windows, place a git repo with ~1000-line Python files in a user folder (e.g., C:\Users\<you>\Documents\<repo>).
Select that folder in Cowork; Cowork mounts it at /sessions/<id>/mnt/<name> via virtiofs.
In the sandbox, run against a specific file:

wc -c <file> — reports a byte count smaller than the host's.
git hash-object <file> — returns a SHA different from git ls-tree HEAD <file>.
git diff HEAD -- <file> — shows large deletions that don't exist on the host.
python -m py_compile <file> — fails with SyntaxError at the truncation boundary.

In host PowerShell, the same commands report the file as clean, hash matches HEAD, compiles cleanly.

Key detail that made the bug hard to diagnose: the .git/index mtime did reflect live host activity inside the sandbox — so a standard "is the mount stale?" check passed. The staleness was selective to specific working-tree files, not the whole mount. This allowed two Claude sessions with different views of the same path to argue past each other across multiple rounds.
Impact: If a user asks Claude inside Cowork to run a build/publish command (twine upload, npm publish, docker build) against a folder with this discrepancy, Claude would package the corrupted sandbox view and ship it to a public registry. This nearly happened on the cloakllm v0.6.3 release.
Error message:
$ python3 -m py_compile server.py
File "server.py", line 731
"""
^
SyntaxError: unterminated triple-quoted string literal (detected at line 735)
EXIT=1
(file on host disk was 38,869 bytes, ended cleanly with if __name__ == "__main__": mcp.run(); sandbox view was 30,917 bytes, truncated mid-docstring)
Environment:

Windows host: [put your Windows version here]
Mounted path: C:\Users\97250\Documents\cloakllm
Sandbox path: C:\Users\97250\Documents\cloakllm
Filesystem: virtiofs via fuse
Claude desktop app version: [from Help → About or equivalent]
Session type: Cowork mode

Workaround: always run publish/build commands from the host terminal, not from Claude inside Cowork, until this is resolved. Restarting the Cowork session may re-sync the mount, but I didn't get to verify.

Environment Info

  • Platform: win32
  • Terminal: vscode
  • Version: 2.1.110
  • Feedback ID: bf22aca8-f73d-40b4-8b13-05300c956cb8

Errors

[]

View original on GitHub ↗

8 Comments

0xbrainkid · 4 months ago

This is a dangerous split-brain filesystem failure: the host and the sandbox are presenting different realities for the same path, and the divergence is selective enough to evade simple freshness checks.

That selective aspect is what makes it especially serious. If the entire mount were stale, users would notice quickly. But when .git/index mtimes appear current while specific working-tree files are truncated or stale, the sandbox looks healthy enough to trust right up until a build, diff, or publish step acts on corrupted bytes.

The near-miss you describe is exactly why this is more than a developer inconvenience. Once packaging/publish commands run against the sandbox view, the product can ship artifacts based on a false version of reality.

So the core failure is not just virtiofs correctness. It is trust in execution context:

  • host says file is clean
  • sandbox says file is modified/truncated
  • both are treated as authoritative by different Claude sessions

At that point, agent reasoning becomes unsafe because the substrate itself is inconsistent.

A strong mitigation would be some kind of host-vs-sandbox verification guard before destructive or release actions in Cowork, especially when git/object hashes disagree. More broadly, Cowork should never allow silent split-brain between host and sandbox on ordinary file reads. If consistency cannot be guaranteed, the UI needs to surface that clearly before any build/publish workflow proceeds.

cloakllm · 4 months ago

Thanks - you've framed this exactly right, and the "trust in execution context" phrasing captures what's actually scary about it better than I did.

A couple of things from my end that might be useful to engineering:
The divergence is even more insidious than just file reads. In my case, the sandbox's git plumbing was internally consistent with the broken view - git hash-object, git status, git diff --stat, and python -m py_compile all agreed that the file was modified and truncated. Nothing inside the sandbox could have told me the view was wrong; it took the user running git hash-object from a host PowerShell window to establish ground truth. So any mitigation that relies on the agent detecting the split-brain from inside is going to fail. The check has to be either host-side or cross-boundary by design.

A minimal version of your "verification guard" that would have saved this release: before any Cowork agent runs a command matching a publish/upload/distribute pattern (twine upload, npm publish, docker push, cargo publish, gh release, etc.), have the UI prompt a one-line host-side hash check against a handful of files the agent has read or modified recently, and refuse to proceed on mismatch. Even blunter: require explicit user confirmation from the host UI for any network-publishing command, with a "file consistency verified" badge. The failure mode here isn't going to be caught by heuristics; it needs a hard gate.

Second-order: as a user workaround until this is fixed, I'd suggest the Cowork docs explicitly warn against running registry-publish commands from inside the sandbox, and steer users toward CI-triggered releases or host-terminal publishing. CI dodges the issue entirely because it checks out from origin in a fresh container - no host/sandbox split to diverge.

Happy to test repros against future Cowork builds if it would help confirm the fix.

tisalvadores · 3 months ago

_Claude Assisted Bug Report_

Confirming this is still happening on current Cowork (Claude Code 2.1.138, bindfs 1.14.7 in the sandbox). Your near-incident almost shipping corrupted bytes to PyPI is a particularly sharp example of why this matters in practice — the silent-truncation symptom you observed (30,917 of 38,869 bytes) is one case of a broader cache pathology where Cowork's bindfs mount holds the last sandbox-originated state of a file and doesn't invalidate when the underlying file changes.

Reproduced the pathology directly on #55206 in a coordinated PowerShell-vs-sandbox test — host writes 16 bytes, sandbox sees stale 100-byte size with the new content padded by 84 null bytes, cache TTL >111 seconds, no manual sandbox-side flush invalidating it. Posted detailed analysis there tying this issue and the rest of the read-side cluster (#38993, #41710, #42520, #45433) to the write-side EPERM cluster (#55206). Independent bugs, independent root causes, but co-located on the same bindfs mount.

Jeffreynuez · 3 months ago

Still reproducing as of 2026-05-26 on Cowork for Windows. Reporting a fresh repro that extends the originally-filed symptoms in two ways: (a) the cache divergence is bidirectional — bash-side reads serve stale/truncated views of host writes, AND bash-side writes (git checkout HEAD -- <path>) silently fail to propagate to the host disk — and (b) bash-side git status lists fewer modified files than the host-side disk actually has, which means a git add . && git commit from inside Cowork bash produces an incomplete commit that looks like the feature shipped but doesn't include the bulk of the changes.

Repro

In a single Cowork session on a Windows-mounted working folder (not OneDrive-synced, plain C:\Users\<me>\Desktop\<folder>\):

  1. Used Anthropic's Edit tool to modify 5 Python files (each between 250–500 lines): added a new import + replaced one large function body.
  2. The Edit tool reported "successfully updated" for each.
  3. Anthropic's Read tool subsequently showed the full new content on every file — confirming the host disk received the writes.
  4. GitHub Desktop (Windows-side, reads the host disk directly) showed all 8 modified files ready to commit, with the expected diffs.
  5. Inside Cowork bash, git status listed only 3 of the 8 as modified. The other 5 files appeared unmodified despite the host having new content.
  6. cat <file> and wc -l <file> from bash showed truncated content cut mid-statement (e.g. db.query(PasswordResetTo).
  7. git update-index --refresh did not resolve the discrepancy.
  8. Issuing git checkout HEAD -- <one of the 5 files> from bash returned exit 0 but did not change the host-side file — GitHub Desktop continued to show it as modified with the post-Edit content. The bash write was absorbed by the bindfs cache layer and never reached the underlying virtiofs/host file.

Why this is dangerous, not just annoying

If the user trusts Cowork bash for the commit step, they get a commit that contains:

  • The model files the agent wrote (visible to bash because the agent used Python via bash, which bypasses the Edit-tool path and propagates correctly)
  • A new service file (visible because it's untracked, so bash sees the inode regardless)
  • None of the 5 router/service modifications that actually implement the feature

The commit would push, CI would pass (Python imports are still valid on disk), and the broken state only surfaces at runtime when the lockout the commit claims to ship doesn't actually fire. A collaborator pulling that commit gets a working tree where the routers don't reference the new service module at all.

Workaround that actually worked

Closed Cowork bash entirely for the commit step and used GitHub Desktop on Windows, which reads the host disk directly. The host-side disk had all 8 modifications correctly, so the GitHub Desktop view + commit was complete and accurate.

Environment

  • Windows 11
  • Claude Code Cowork (latest as of 2026-05-26)
  • Working folder: C:\Users\<me>\Desktop\US apps\<repo>\ (no OneDrive sync, no third-party AV other than Defender, no Indexer exclusion at the time of repro)
  • Mount stack inside the Cowork Linux VM (from mount output):
  • virtiofs from C:\Users\<me>\AppData\Local\Packages\Claude_<hash>\LocalCache\Roaming\Claude\local-agent-mode-sessions\.../<working-folder>
  • bindfs (FUSE wrapper, default_permissions,allow_other) → exposed at /sessions/<vm>/mnt/<working-folder>

Bindfs appears to be the layer with the broken cache invalidation, consistent with the user analysis on #55206 that traced the EPERM-on-unlink bug to bindfs --delete-deny. Both symptoms are colocated on the same mount layer.

Cross-references

  • Same bug class: #42520 (closed as dup of #38993), #58023 (open), #56105 (open), #59564 (open)
  • Sibling bug on the same bindfs layer (--delete-deny): #55206, #61343
  • Closed-but-still-active (per 2026-05-16 comment on #55877 noting the migration from rclone to virtiofs didn't fix it): #40264, #42520, #55877

Happy to provide the verbatim mount output, file sizes, and commit SHAs from this session if it helps a fix land. The bug is reproducible at will: any Cowork session that uses the Edit tool on 4+ files of nontrivial size in a single working folder will eventually hit it.

lucatrading21-debug · 3 months ago

+1 evidence: Cowork virtual mount serves a stale file snapshot after Windows-side git checkout

Dual-PC workflow (Windows host + Cowork Linux sandbox). After a Windows-side git checkout HEAD -- <file> restores a file in the Windows working tree, the Cowork mount keeps serving the pre-checkout snapshot:

  1. Windows: git checkout HEAD -- SESSION_LOG.md → file canonical in Windows working tree
  2. Cowork sandbox: wc -l SESSION_LOG.md → still the old line count (stale)
  3. Cowork sandbox: stat shows mtime frozen at session-open time, not the Windows post-checkout mtime

Implication: the mount appears to bind to the file snapshot at session-open / first-read time, not live-tracking host filesystem changes. Data-loss risk: if the agent then Edits/Writes that file Cowork-side, it overwrites the canonical Windows content with the stale snapshot.

Only effective mitigation found: close + reopen the Cowork session (in-session re-read does not refresh).

Asks: (1) invalidate mount cache on host mtime change (inotify-equivalent), or (2) expose a mount_refresh(path) operation callable after host-side git operations, and (3) document the limitation.

lucatrading21-debug · 3 months ago

+1 — adding a concrete data-loss instance (not just a near-miss), plus a note on likely duplicates.

Environment: Claude desktop "Cowork" mode on Windows, working folder mounted read/write into the Linux sandbox.

Repro (recurrent for us, ~5th occurrence across sessions):

  1. File X committed via Code CLI on the host; HEAD is correct on disk.
  2. A new Cowork session opens. The mounted view of X is STALE — it reflects a pre-checkout revision, not current HEAD.
  3. An Edit/Write from the Cowork side then writes back over the stale view, TRUNCATING the file.

Latest incident: a 237-line file was silently truncated to 227 by a Cowork-side Edit. HEAD on the host was intact, so we recovered with git show HEAD:<file> > <file> (sandbox bash) then re-applied the edit via bash heredoc.

Triage notes:

  • close + reopen of the session does NOT reliably refresh the stale mount.
  • the cache layers appear inconsistent: in our case wc -l via sandbox bash read FRESH while the Edit/Write tool still operated on a STALE buffer — but other reports (#40191) show wc -l ALSO returning the truncated count. So the bash view and the file-tool view can diverge unpredictably.
  • this looks like the same root issue as #41710, #40264, #38993, #55877, #40191, #45433 — likely worth consolidating.

Mitigation we now enforce: never Edit/Write host-tracked files from the Cowork side; route all writes through sandbox bash (git show HEAD: + heredoc) or do them host-side in Code CLI.

lucatrading21-debug · 2 months ago

+1 — additional deterministic evidence tying this mount-read truncation to the
"byte-conservation cap" mechanism (#53940).

Environment: Cowork desktop on Windows host. Repo files committed LF; host disk and
git blobs are byte-perfect. Reading TRACKED repo files through the bash workspace mount
(/sessions/<id>/mnt/...) via cat/python returns a corrupted view, while
git show HEAD:<file> and the Windows host are clean.

Exact, reproducible signature on files I never modified:

sandbox_read_bytes == blob.replace(b"\n", b"\r\n")[:len(blob)] # -> True

The mount converts LF->CRLF on read AND caps the buffer at the blob's ORIGINAL byte
length: it injects N CR bytes (one per line) and drops exactly N bytes off the tail.
Net effect: identical byte count, CRs added, end-of-file content silently lost. When
the cut lands mid multi-byte char it surfaces as "invalid UTF-8" (lone 0xC2); when it
lands on ASCII it passes UTF-8 validation but is still truncated (so the corruption is
wider than a UTF-8 scan suggests).

This unifies the "virtiofs serves truncated content, host clean" reports (#50873,
#41710, #40191, #38993) with the byte-conservation cap (#53940) and the Windows CRLF
behavior (#38887): the CRLF expansion is precisely what the byte cap consumes.

Detection that works: cat file | md5sum vs git show HEAD:file | md5sum differ;
git show HEAD:file | tr -d '\r' | md5sum vs cat file | tr -d '\r' | md5sum confirms
real content loss beyond line endings.

Impact in my case: I nearly committed a "UTF-8 fix" + version bump for 13 files that were
100% clean in git — the corruption existed only in the mount's read view. Workaround:
read repo bytes via git show HEAD:<path> (never the bash mount); verify any writes
host-side with git status.

rstribrn · 1 month ago

Corroboration, with a reliable refresh workaround.

Same signature on our side: after a file is written correctly on the Windows host, the sandbox mount serves a stale/truncated view of specific files while the mount as a whole looks fresh. In-sandbox wc -c / wc -l / md5sum / py_compile disagree with the host copy; the truncation typically ends mid-line/mid-word. stat shows Blocks != 0 (not a dehydrated placeholder), so this is a coherence bug, not cloud hydration.

Reproduced on plain NTFS (not only OneDrive), which suggests the host-share layer itself, independent of the Cloud Files API.

The staleness is inode-bound: a newly created file (fresh inode) reads correctly via bash, while the stale inode keeps serving the old view. A mv rename round-trip (mv x y && mv y x) reliably refreshes the view (verified byte-identical). Notably, a native file-tool full read does not reliably re-hydrate the sandbox view of an already-cached inode, and starting a new session/remount does not reliably help either.

Ask: invalidate the mount-side cache on host mtime/size change (or validate length/checksum against the host on open), so the sandbox never serves a stale inode silently.

Showing cached comments. Read the full discussion on GitHub ↗