[BUG] Write post-write verification false-positives on WSL2 / local ext4 — bogus "bytes on disk" (== len(path)+96, or 0) and false "silently truncated" for files that are correct
Preflight Checklist
- [x] I have searched existing issues and this specific failure mode hasn't been reported
- [x] This is a single bug report
- [x] First seen on the stable release (2.1.181) and still reproduces after upgrading to 2.1.195 — not fixed
Summary
On WSL2 with the repo on a local ext4 disk (not a network drive, not a cloud-synced folder), the Write tool's post-write verification fires on essentially every write and returns:
Write verification failed: <path> is N bytes on disk, expected M. The filesystem may have silently truncated the write (network drive / cloud sync).
…but the file on disk is 100% correct. This is a false positive in the verification layer, not real truncation.
This is not fixed. It was first hit on 2.1.181 — the stable-channel release — and still reproduces after upgrading to 2.1.195 (a build ahead of the stable tag; 2.1.195 is not itself the stable channel). So the issue is present on stable and remains unresolved after upgrading.
The reported "N bytes on disk" is provably bogus: across many writes it is exactly len(absolute_path) + 96, a constant offset that is completely independent of the file's actual content (it tracks the path length, not the file). In a subset of cases it instead reports 0.
This is the inverse of the known Windows/Cowork corruption bugs (#64598, #53940): there the detector hides real corruption; here the detector invents corruption that doesn't exist. The error message even reuses the "network drive / cloud sync" wording from the 2.1.181 changelog entry ("Fixed Write/Edit producing 0-byte or truncated files on network drives and cloud-synced folders") — ironically, 2.1.181 is exactly where this false positive was first observed, so that fix did not address (and may be the source of) this behavior. It makes the error look like a regression of that fix even though the file is fine and the disk is local ext4.
Environment
- Claude Code: first observed on 2.1.181 (stable-channel release); still reproduces on 2.1.195. 2.1.195 is ahead of the stable tag and is not the stable channel — i.e. the bug exists on stable and is still unfixed after upgrading.
- Platform: Linux, kernel
6.1.0-32-cloud-amd64, WSL2 (Windows interop present — notification hooks invoke/mnt/c/Windows/System32/cmd.exe+ PowerShell) - Filesystem: repo and
~/.claudeare on the same local ext4 device (df -T->ext4). No network mount, no OneDrive/Dropbox/iCloud, not under/mnt/c. - Not Cowork. Plain CLI, no sandbox/virtiofs mount.
Reproduction
- In Claude Code on WSL2 with the project on local ext4, use the Write tool to create any new file with a few lines of text (ASCII or multibyte — both reproduce).
- The tool returns the
Write verification failed ... silently truncated (network drive / cloud sync)error. - Verify out-of-band:
wc -c <path>-> equals the EXPECTED value M (file is correct)cat <path>-> full content present, nothing truncated
- Compare the tool's reported
Nagainstlen(absolute_path) + 96. They match exactly. (OrN == 0in a subset of cases.)
100% trigger rate: in my run 6/6 writes raised the error; 6/6 files were correct on disk.
Evidence
expected always equals the real content size (wc -c). The reported "on disk" N never does — it equals len(path)+96:
| file (under a 39-char dir prefix) | real size (wc -c) | tool expected | tool "on disk" N | len(abs_path) | len(path)+96 |
|---|---|---|---|---|---|
| .write_probe_195.txt (CJK + em-dash) | 130 | 130 | 155 | 59 | 155 |
| .write_probe_ascii.txt (pure ASCII) | 57 | 57 | 157 | 61 | 157 |
| p1.txt | 2 | 2 | 141 | 45 | 141 |
| p2_longername_padding_xxxxx.txt | 2 | 2 | 166 | 70 | 166 |
| p3b.txt | 491 | 491 | 142 | 46 | 142 |
| p3.txt (1st attempt) | 491 | 491 | 0 | - | - |
Controlled variation proves the offset is on the path, not the content:
p1.txt(2 bytes) andp3b.txt(491 bytes) — content differs by 489 bytes, both reportlen(path)+96.p1.txtvsp2_longername_padding_xxxxx.txt— same 2-byte content, paths differ by 25 chars -> reportedNdiffers by exactly 25 (141 vs 166).
So N is derived from a path-containing string, not from reading the file. The +96 is a constant boilerplate offset; it looks like the verifier measures the length of a path-embedding string (e.g. the File created successfully at: <path> (file state is current ...) success message) instead of fs.statSync(path).size / a re-read of the bytes.
Data integrity / impact
- No permanent data loss observed — all 6 files ended up correct on disk.
- But the verifier is a broken detector in both directions: its byte count is bogus, so it also cannot detect a real truncation. It just emits a scary, misleading error on healthy writes.
- The
N == 0cases coincide with a read-after-write visibility lag: immediately after Write returned,ls/wcshowed the file missing/empty, then it appeared a moment later (an async "File created successfully" notification arrived late). Same family as #63797 ("Bash/Read results intermittently return empty then flush late on Linux"). The verifier likely reads the file back too eagerly, before the write is visible — and when it doesn't read 0, it falls back to measuring the wrong (path-derived) string.
Why this is distinct from existing issues
- #64598 (Read cache masks on-disk corruption, Windows/Cowork) — opposite direction; that detector hides real corruption, this one fabricates fake corruption. Mine is plain WSL CLI, no Cowork.
- #53940 / #66142 / #65229 / #67585 — real truncation/data loss on Windows + Cowork/OneDrive. Mine has no real corruption and no network/cloud FS.
- #49805 (closed) — Write reports success but file missing on Windows. Mine reports failure on files that are correct.
- #63797 / #36038 — Bash/Read empty-then-late-flush on Linux. Same underlying read-after-write lag that triggers my
N == 0cases, different surface (this report is about the Write verifier). - Possibly belongs to the master ticket #54891 family of "silent write/verify failure modes," but is not one of its listed splits (not O_TRUNC, UTF-8 boundary, CRLF, nor concurrency).
Suspected root cause
The post-write verification compares expected = Buffer.byteLength(content) against a value that is not the actual on-disk size:
- When the just-written file isn't yet visible (WSL2 read-after-write lag), the read-back returns
0. - Otherwise the compared "size" is a path-derived string length (
len(path)+96) — i.e. it measures the wrong object, most likely the success-message string (which embeds the absolute path) rather thanfs.statSync(path).size.
Either way the comparison is structurally wrong and produces false truncation errors.
Suggested fix
- Verify with
fs.statSync(path).size(or re-read + hash) againstBuffer.byteLength(content)— never against any string that embeds the path. - If the read-back can legitimately lag (WSL2 / 9p / drvfs), add a short bounded retry (re-stat after a few ms) before declaring truncation, instead of trusting a single eager read.
- Only emit the "network drive / cloud sync" copy when the path is actually on such a mount.
Workaround (for other affected users)
Treat this Write verification failed ... silently truncated (network drive / cloud sync) error as a false positive on WSL2/local ext4. Do not rewrite the file (it's already correct). Confirm with wc -c / re-Read / import / pytest. If you must consume the file immediately after the Write, allow for a brief read-after-write delay (re-check once) rather than assuming corruption.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗