claude-code - 💡(How to fix) Fix Write tool silently pads files with null bytes; content appears to revert across turns [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#52883Fetched 2026-04-25 06:18:19
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
0
Timeline (top)
labeled ×4commented ×1

When the Write tool is used to create or overwrite a Markdown file containing an instruction set (heredoc-style content, ~5–8 KB), the file on disk appears to receive the correct bytes at the head and then is padded with hundreds to thousands of NULL bytes (0x00) at the tail. Subsequent turns may also see the file's semantic content silently swapped for the content of a sibling file — with no user action, no tool call, and no visible operation in between.

The agent's self-checks pass because:

  • Read returns the prefix of the file as UTF-8, hiding the null padding.
  • The Write tool reports file has been updated successfully.
  • Size matches expectations if the caller doesn't notice the extra nulls.

Only a forensic byte-level check (wc -c, hexdump, tr -d -c '\0' | wc -c) reveals the corruption.

Error Message

  1. Post-write integrity check. After every Write, the tool should re-read the first and last 256 bytes from disk and confirm the new content contains both the prefix and the null-terminated-free suffix the tool intended to write. On mismatch, return an error rather than success.
  2. Null-byte detection and refusal. If a Write's input contains a null byte literal, refuse the write. If a Write's disk output contains a null byte literal when the input did not, treat as a storage layer failure and surface a specific error code.

Root Cause

The agent's self-checks pass because:

  • Read returns the prefix of the file as UTF-8, hiding the null padding.
  • The Write tool reports file has been updated successfully.
  • Size matches expectations if the caller doesn't notice the extra nulls.

Fix Action

Fix / Workaround

Workaround that worked

  1. Post-write integrity check. After every Write, the tool should re-read the first and last 256 bytes from disk and confirm the new content contains both the prefix and the null-terminated-free suffix the tool intended to write. On mismatch, return an error rather than success.
  2. Null-byte detection and refusal. If a Write's input contains a null byte literal, refuse the write. If a Write's disk output contains a null byte literal when the input did not, treat as a storage layer failure and surface a specific error code.
  3. Unique file-write buffers per file. Mode B suggests a write buffer may be keyed by something other than absolute path (perhaps relative path under the folder). Audit the buffering layer.
  4. Invalidate Read caches aggressively after Write. Mode C's symptom (post-write reads succeed, next-turn reads fail) strongly suggests a stale cache.
  5. Document the zipfile.writestr workaround in tool help for cases where agents need to produce multi-file artifacts.

Code Example

$ stat --printf '%s\n' skills/push-dashboard_git/SKILL.md
7755

$ tr -d -c '\0' < skills/push-dashboard_git/SKILL.md | wc -c
356

---

import zipfile

MD_BODY = r"""---
name: push-dashboard
description: ...
---
# push-dashboard
...
"""

with zipfile.ZipFile("/tmp/push-dashboard.skill", "w",
                      compression=zipfile.ZIP_DEFLATED) as z:
    z.writestr("push-dashboard/SKILL.md", MD_BODY)
RAW_BUFFERClick to expand / collapse

Bug report #2 — Write tool silently pads files with null bytes; content appears to revert across turns

Environment: Cowork desktop (Claude Agent SDK), Windows 11, OneDrive-synced workspace Date observed: 2026-04-24 (same day as bug report #1) Severity: High — silent data loss, exceptionally difficult to detect. Relation to prior report: Follow-up to CLAUDE_EDIT_TOOL_BUG_REPORT.md filed earlier today. That report covered Edit; this one covers Write, and adds three new failure modes discovered while trying to work around the first bug.

Summary

When the Write tool is used to create or overwrite a Markdown file containing an instruction set (heredoc-style content, ~5–8 KB), the file on disk appears to receive the correct bytes at the head and then is padded with hundreds to thousands of NULL bytes (0x00) at the tail. Subsequent turns may also see the file's semantic content silently swapped for the content of a sibling file — with no user action, no tool call, and no visible operation in between.

The agent's self-checks pass because:

  • Read returns the prefix of the file as UTF-8, hiding the null padding.
  • The Write tool reports file has been updated successfully.
  • Size matches expectations if the caller doesn't notice the extra nulls.

Only a forensic byte-level check (wc -c, hexdump, tr -d -c '\0' | wc -c) reveals the corruption.

Three distinct failure modes observed in the same session

Mode A — Null-byte padding after Write

$ stat --printf '%s\n' skills/push-dashboard_git/SKILL.md
7755

$ tr -d -c '\0' < skills/push-dashboard_git/SKILL.md | wc -c
356

The file is 7755 bytes; 356 of them are literal \x00. The Write tool reported success. Reading the head via head shows expected Markdown. grep marks the file as "binary file matches" because of the embedded nulls.

This is the same shape as the Edit truncation from report #1, but delivered by Write rather than Edit.

Mode B — File reverts to a different file's contents between turns

Timeline in a single Cowork session:

  1. Turn A — Write tool called on skills/push-dashboard_git/SKILL.md with content starting name: push-dashboard_git\n.... Python immediately re-reads the file: confirmed name: push-dashboard_git on line 2, zero null bytes, size 5659 bytes.
  2. Turn B — Write tool called on a DIFFERENT file, skills/push-dashboard/SKILL.md, with api-based content starting name: push-dashboard\n....
  3. Turn C — Python re-reads skills/push-dashboard_git/SKILL.md (the file from turn A that we already verified).
    • First two lines are now --- / name: push-dashboard — not push-dashboard_git.
    • File has 356 null bytes it did not have in turn A.
    • Neither the user nor the agent touched this file between turns A and C.

The most likely explanation is that the Write tool's backing buffer is shared across files in the same folder, and the second write is bleeding into the first file's on-disk representation.

Mode C — Successful Write followed by silent revert

Even when Write appears to succeed and a post-write Python re-read confirms correct content in the same Python script, a Python script in the next turn sometimes reads the pre-write content. Behaviour consistent with a write buffer that is never flushed to disk, or a filesystem watcher / OneDrive sync layer that silently reverts files it has already uploaded. Unclear whether this is a Claude tool bug or a Windows file-system quirk — but it is triggered only on files Claude just wrote, not files written by bash/Python. Bash and Python writes are stable across turns.

Workaround that worked

Do not write the file at all. Construct the zip archive entirely from Python string literals using zipfile.writestr(archive_path, md_body). The archive on disk is correct; the intermediate SKILL.md file is never created by Claude's tool chain.

import zipfile

MD_BODY = r"""---
name: push-dashboard
description: ...
---
# push-dashboard
...
"""

with zipfile.ZipFile("/tmp/push-dashboard.skill", "w",
                      compression=zipfile.ZIP_DEFLATED) as z:
    z.writestr("push-dashboard/SKILL.md", MD_BODY)

Six previous attempts using Write (to .md) followed by zipfile.write() (reading from disk) produced corrupted archives — because the source .md on disk was already corrupted. The moment we skipped the file-write step and went straight from string to zip, the result was correct on the first try, identical across turns, md5-stable.

What reliably triggers the bug in our testing

  • File type: Markdown (.md). The same content written as .txt was not observed to be corrupted — though this may be confirmation bias (fewer .txt writes in our workflow).
  • File size: above ~4 KB. Smaller files usually survive.
  • Workflow: a Write on file A, followed in a later turn by a Write on sibling file B in the same folder. File A's contents are the ones that revert / get nulls.
  • The host folder is OneDrive-synced. Reproduction in a non-synced folder was not tested in this session but was tested briefly (staging in outputs/) and the corruption still occurred there — so OneDrive is probably not the sole cause, though it may contribute.

Proposed triage

  1. Post-write integrity check. After every Write, the tool should re-read the first and last 256 bytes from disk and confirm the new content contains both the prefix and the null-terminated-free suffix the tool intended to write. On mismatch, return an error rather than success.
  2. Null-byte detection and refusal. If a Write's input contains a null byte literal, refuse the write. If a Write's disk output contains a null byte literal when the input did not, treat as a storage layer failure and surface a specific error code.
  3. Unique file-write buffers per file. Mode B suggests a write buffer may be keyed by something other than absolute path (perhaps relative path under the folder). Audit the buffering layer.
  4. Invalidate Read caches aggressively after Write. Mode C's symptom (post-write reads succeed, next-turn reads fail) strongly suggests a stale cache.
  5. Document the zipfile.writestr workaround in tool help for cases where agents need to produce multi-file artifacts.

Ask

A minimal repro is available on request — we still have the complete session transcript from today with all tool inputs. Please let us know which layer handles the Write call (Claude Code harness, Cowork local agent, Windows-side Node shim, or the storage driver for OneDrive-synced mounts) so we can correlate.


Thank you — the toolchain is clearly powerful; these two bugs are the only ones slowing us down right now, and both produce silent corruption rather than loud failures, which is why they deserve extra attention.

extent analysis

TL;DR

Implement a post-write integrity check to verify the written content matches the intended content, and consider using the zipfile.writestr workaround to avoid file corruption.

Guidance

  • Verify the Write tool's backing buffer is not shared across files in the same folder, as suggested by Mode B.
  • Check for null-byte detection and refusal in the Write tool to prevent silent data corruption.
  • Investigate the caching layer to ensure Read caches are invalidated aggressively after Write operations.
  • Consider implementing a unique file-write buffer per file to prevent cross-file contamination.
  • Use the zipfile.writestr workaround to produce multi-file artifacts without writing to disk.

Example

import zipfile

MD_BODY = r"""---
name: push-dashboard
description: ...
---
# push-dashboard
...
"""

with zipfile.ZipFile("/tmp/push-dashboard.skill", "w",
                      compression=zipfile.ZIP_DEFLATED) as z:
    z.writestr("push-dashboard/SKILL.md", MD_BODY)

Notes

The root cause of the issue is unclear, but it appears to be related to the Write tool's handling of file writes and caching. The zipfile.writestr workaround provides a reliable way to produce multi-file artifacts without writing to disk.

Recommendation

Apply the zipfile.writestr workaround to avoid file corruption, and implement a post-write integrity check to verify the written content matches the intended content. This will help prevent silent data corruption and ensure the reliability of the toolchain.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix Write tool silently pads files with null bytes; content appears to revert across turns [1 comments, 2 participants]