[Cowork file tools silently truncate / null-pad writes on the Windows workspace mount]
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?
<html>
<body>
<!--StartFragment--><h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="14:1-14:11;487-497">Summary</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="15:1-21:14;498-995">In Cowork mode on Windows, the file-editing tools (Edit / Write) intermittently
return <strong>success</strong> for a write that actually landed on disk <strong>corrupted</strong> — either
truncated mid-content or padded with trailing NUL bytes. This is a <em>write-side,
on-disk</em> corruption, distinct from the already-reported stale/truncated <strong>read</strong>
defects (#41710, #42520, #45433, #50873) and from the <strong>unlink-denied</strong> defect
(#55206). The corruption survives to the host filesystem; it is not just a stale
sandbox view.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="23:1-23:28;997-1024">Two failure modes observed:</p>
<ol class="[li_&]:mb-0 [li_&]:mt-1 [li_&]:gap-1 [&:not(:last-child)_ul]:pb-1 [&:not(:last-child)_ol]:pb-1 list-decimal flex flex-col gap-1 pl-8 mb-3" data-sourcepos="25:1-30:52;1026-1437">
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="25:1-27:39;1026-1221"><strong>Silent truncation</strong> — the write returns success but the file is cut off
mid-content (missing trailing bytes, no closing tag/brace). Losses of 20–30%
of trailing content have been seen.</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="28:1-30:52;1222-1437"><strong>Trailing NUL-byte padding</strong> — the write returns success and the file <em>looks</em>
correct to <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">wc</code>/<code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">tail</code> (it ends with a proper newline), but hundreds of <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">\x00</code>
bytes have been appended after the real content.</li>
</ol>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="32:1-32:44;1439-1482">Why this is high-impact and easy to miss</h2>
<ul class="[li_&]:mb-0 [li_&]:mt-1 [li_&]:gap-1 [&:not(:last-child)_ul]:pb-1 [&:not(:last-child)_ol]:pb-1 list-disc flex flex-col gap-1 pl-8 mb-3" data-sourcepos="33:1-41:41;1483-2137">
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="33:1-35:81;1483-1718"><strong>A size-only verification can pass.</strong> In at least one case the truncation
dropped exactly as many bytes as the edit added, so the resulting file size
matched the expected size — only a byte-for-byte content comparison caught it.</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="36:1-38:54;1719-1934"><strong><code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">tail</code> and <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">wc</code> miss the NUL padding</strong> because the real content ends with a
newline immediately before the NUL run, so line-aware tools see a clean ending.
Detection requires <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">tr -d '\0' | wc -c</code> vs <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">wc -c</code>.</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="39:1-41:41;1935-2137"><strong>The Read tool cannot be trusted to verify the write</strong>, because it can return
cached/intended content rather than what is on disk. Verification must be done
from a shell that reads the raw bytes.</li>
</ul>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="43:1-44:78;2139-2296">Net effect: every occurrence forces a recover-from-git → re-apply → multi-check
verify cycle. It has recurred on a roughly weekly basis across many projects.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="46:1-46:15;2298-2312">Environment</h2>
<ul class="[li_&]:mb-0 [li_&]:mt-1 [li_&]:gap-1 [&:not(:last-child)_ul]:pb-1 [&:not(:last-child)_ol]:pb-1 list-disc flex flex-col gap-1 pl-8 mb-3" data-sourcepos="47:1-51:75;2313-2643">
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="47:1-47:64;2313-2376">Cowork mode (Claude desktop), Windows host, Linux sandbox VM.</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="48:1-49:38;2377-2486">Workspace is the user's Windows folder, exposed to the sandbox over a
<strong>virtiofs + bindfs</strong> mount bridge.</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="50:1-51:75;2487-2643">Same mount layer implicated in the unlink-denied defect (#55206) and a measured
~66x write-speed penalty (4.5 MB/s mounted vs ~297 MB/s sandbox-native).</li>
</ul>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="53:1-53:57;2645-2701">Observed occurrences (representative, not exhaustive)</h2>
<div class="overflow-x-auto w-full px-2 mb-6" data-sourcepos="54:1-62:65;2702-3404">
Date | File(s) | Mode
-- | -- | --
2026-06-14 | three source files in one project | truncation
2026-06-13 | root CLAUDE.md AND project-tiers.md | truncation (byte count matched the added bytes — a size check would have passed)
2026-06-13 | engine.py (lost an entire function block) | truncation → silent no-write bug
2026-06-12 | archive.html (ended mid-statement, no </html>) | truncation
2026-06-09 | a Markdown plan (172 NUL bytes appended) | NUL padding
2026-06-06 | a repo's .git/index (NUL-padded on disk) | NUL padding — proof corruption reaches host disk, not a stale read
May 2026 | multiple files | truncation, 20–30% trailing loss
</div>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="64:1-64:36;3406-3441">Steps to reproduce (best-effort)</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="65:1-65:82;3442-3523">The corruption is intermittent, which is the core difficulty. General conditions:</p>
<ol class="[li_&]:mb-0 [li_&]:mt-1 [li_&]:gap-1 [&:not(:last-child)_ul]:pb-1 [&:not(:last-child)_ol]:pb-1 list-decimal flex flex-col gap-1 pl-8 mb-3" data-sourcepos="66:1-72:68;3524-3980">
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="66:1-66:94;3524-3617">In Cowork on Windows, open a workspace backed by a Windows folder (virtiofs+bindfs mount).</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="67:1-68:31;3618-3730">Use the Edit or Write tool to write or modify a file on that mount, especially
larger or structured files.</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="69:1-69:42;3731-3772">Observe that the tool reports success.</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="70:1-72:68;3773-3980">Verify the on-disk bytes from a raw-byte reader (not the Read tool):
<ul class="[li_&]:mb-0 [li_&]:mt-1 [li_&]:gap-1 [&:not(:last-child)_ul]:pb-1 [&:not(:last-child)_ol]:pb-1 list-disc flex flex-col gap-1 pl-8 mb-3" data-sourcepos="71:4-72:68;3848-3980">
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="71:4-71:68;3848-3912">truncation: on-disk size < expected, or content ends mid-line;</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="72:4-72:68;3916-3980">NUL padding: <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">cmp</code> of <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">wc -c</code> vs <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">tr -d '\0' | wc -c</code> differs.</li>
</ul>
</li>
</ol>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="74:1-74:86;3982-4067">A reliable trigger is not yet isolated. Frequency is roughly weekly under normal use.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="76:1-76:56;4069-4124">Current user-side mitigation (workaround, not a fix)</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="77:1-81:11;4125-4444">The user's workflow now bans the Edit/Write tools for any file on the mount and
routes every write through a shell heredoc with a three-check verifier
(no-NUL-in-temp, no-NUL-in-target, sizes-equal) plus an optional host-side MD5
cross-check. This is effective but costly and easy to forget; it should not be
necessary.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="83:1-83:13;4446-4458">Requested</h2>
<ol class="[li_&]:mb-0 [li_&]:mt-1 [li_&]:gap-1 [&:not(:last-child)_ul]:pb-1 [&:not(:last-child)_ol]:pb-1 list-decimal flex flex-col gap-1 pl-8 mb-3" data-sourcepos="84:1-89:82;4459-4885">
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="84:1-85:38;4459-4578">Confirm whether Edit/Write flush+fsync and verify byte length before reporting
success on a bindfs-backed target.</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="86:1-87:74;4579-4727">Treat the NUL-padding and truncation as on-disk write corruption (not a
read-cache artifact), given the <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">.git/index</code> host-disk evidence above.</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="88:1-89:82;4728-4885">If a full fix is not near-term, consider a built-in post-write read-back
verification for mounted targets so the tool fails loudly instead of silently.</li>
</ol>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="91:1-91:18;4887-4904">Related issues</h2>
<ul class="[li_&]:mb-0 [li_&]:mt-1 [li_&]:gap-1 [&:not(:last-child)_ul]:pb-1 [&:not(:last-child)_ol]:pb-1 list-disc flex flex-col gap-1 pl-8 mb-3" data-sourcepos="92:1-93:78;4905-5042">
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="92:1-92:60;4905-4964">#55206 — unlink() denied on the same mount (filed, open).</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="93:1-93:78;4965-5042">#41710, #42520, #45433, #50873 — read-side stale/truncated content (filed).</li></ul><!--EndFragment-->
</body>
</html>
What Should Happen?
Requested
Confirm whether Edit/Write flush+fsync and verify byte length before reporting
success on a bindfs-backed target.
Treat the NUL-padding and truncation as on-disk write corruption (not a
read-cache artifact), given the .git/index host-disk evidence above.
If a full fix is not near-term, consider a built-in post-write read-back
verification for mounted targets so the tool fails loudly instead of silently.
Error Messages/Logs
Steps to Reproduce
Steps to reproduce (best-effort)
The corruption is intermittent, which is the core difficulty. General conditions:
In Cowork on Windows, open a workspace backed by a Windows folder (virtiofs+bindfs mount).
Use the Edit or Write tool to write or modify a file on that mount, especially
larger or structured files.
Observe that the tool reports success.
Verify the on-disk bytes from a raw-byte reader (not the Read tool):
truncation: on-disk size < expected, or content ends mid-line;
NUL padding: cmp of wc -c vs tr -d '\0' | wc -c differs.
A reliable trigger is not yet isolated. Frequency is roughly weekly under normal use.
Current user-side mitigation (workaround, not a fix)
The user's workflow now bans the Edit/Write tools for any file on the mount and
routes every write through a shell heredoc with a three-check verifier
(no-NUL-in-temp, no-NUL-in-target, sizes-equal) plus an optional host-side MD5
cross-check. This is effective but costly and easy to forget; it should not be
necessary.
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
Claude 1.14271.0 (c8f4d8) 2026-06-18T05:47:57.000Z
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
_No response_
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗