◉CLAUDE LABJP
●2.1.302 — Fork subagents are now on by default in claude -p, the Agent SDK and the desktop app. Turn them off with CLAUDE_CODE_FORK_SUBAGENT=0 (10/16)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 43 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.302 — Fork subagents are now on by default in claude -p, the Agent SDK and the desktop app. Turn them off with CLAUDE_CODE_FORK_SUBAGENT=0 (10/16)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 43 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/Claude.ai
◉ Claude.ai/2026-10-19Intermediate

Claude Said the File Was Created, but the Folder Was Empty — A Read-Back Check After Every Write

When a file-creation call reports success but nothing exists on disk, here is the order I use to narrow down the cause, plus a small script that reads back every write.

Claude53MCP56file operationstroubleshooting94verification6cloud sync

One evening I went to open a settings file I had just asked Claude to write, and I stopped. The reply said the file was created. The folder showed nothing, and ls in the terminal showed nothing either.

There was no error anywhere. That was exactly what made my stomach go a little cold. When a failure is visible, you simply redo it. The harder case is believing it succeeded and moving on to the next step.

I was in the middle of tidying store metadata for one of my wallpaper apps, as an indie developer, and asking Claude to write JSON into a folder is a routine part of that. Here is how I narrow down this kind of mismatch, and the small check I now put after every write.

Telling the symptoms apart: "not created" versus "not kept"

I find it easier to split the symptom in two.

SymptomCommon causeFirst thing to check
Reply says success, file exists somewhere elseThe target path differs from what you expectedThe absolute path in the reply, the working directory
Reply says success, file exists nowhereThe write never landed (permissions, a synced folder, connection state)Reading the same path back (ENOENT or not)
Editing existing files works, only new files vanishThe create path behaves differentlyTrying create and edit separately

There is a community report of a filesystem MCP server where only new-file creation returned success without leaving a file. Editing and reading existing files stayed reliable, and relaunching the app did not change it. It was reported under a cloud-synced mount, which caught my attention.

I do not treat that report as a diagnosis. I read it as a clue that the same shape of symptom has been seen, and then I narrow things down in my own environment.

The order I narrow it down

Having a fixed order keeps me calm.

  1. Copy the path from the reply and pass it to ls -l unchanged.
  2. If it is missing, run ls -la on the parent. Is the directory gone, or only the file?
  3. Repeat the same operation in a folder that is not synced, for example under /tmp.
  4. Check whether appending to or editing an existing file works.
  5. Look at the connected tools and their status. If one has dropped, reconnect it.

Step 3 is the pivot. If it only happens in the synced folder, the suspects narrow from the write path to the sync layer. If it also happens locally, I treat it as a tool-side problem.

The fix: read it back right after writing

Before any diagnosis, I put one safeguard in place. If I wrote it, I read it. I look at the file itself, not at the wording of the reply.

This script checks that the expected file exists, is not empty, and contains what I expect. What it solves is simple: instead of trusting "created," it lets the real file decide whether the next step may run.

#!/usr/bin/env bash
# verify_written.sh — read-back check right after a write
# Usage: ./verify_written.sh <path> [expected string]
set -u
 
path="$1"
expect="${2:-}"
 
if [ ! -e "$path" ]; then
  echo "NG: does not exist: $path" >&2
  ls -la "$(dirname "$path")" >&2 2>/dev/null || echo "NG: parent directory not found either" >&2
  exit 1
fi
 
if [ ! -s "$path" ]; then
  echo "NG: file is empty: $path" >&2
  exit 2
fi
 
if [ -n "$expect" ] && ! grep -qF -- "$expect" "$path"; then
  echo "NG: expected content not found: $expect" >&2
  exit 3
fi
 
echo "OK: $(wc -c < "$path") bytes — $path"

I use three distinct exit codes so the caller can tell "missing," "empty," and "wrong content" apart. Even in an unattended run, the log shows where it stopped.

From Claude Code, calling it right after the write feels natural.

# Example: check right after asking for a settings file
./verify_written.sh ./config/app.settings.json '"version"' || echo "needs to be recreated"

If you would rather embed it in Python:

from pathlib import Path
 
 
def verify_written(path: str, expect: str = "") -> None:
    """Check the file on disk. Raise if the write did not stick."""
    p = Path(path)
    if not p.exists():
        raise FileNotFoundError(f"write did not persist: {p}")
    text = p.read_text(encoding="utf-8")
    if not text.strip():
        raise ValueError(f"file is empty: {p}")
    if expect and expect not in text:
        raise ValueError(f"expected content missing: {expect!r}")
 
 
verify_written("./config/app.settings.json", '"version"')

If it still does not work

When the read-back fails and recreating gives the same result, I try three things in order.

  • Move the target outside the sync. Create the file locally, then copy it into the synced folder once it is complete. If that works, the sync layer becomes the likelier cause.
  • Stop creating and start editing. Place an empty template by hand first, then let Claude fill it in by editing. It is a detour that follows the report's observation that editing stayed reliable.
  • Write through another route. If the tool path is unstable, have Claude write with a shell command and run the same check.

None of these is a root-cause fix. Still, with the check in place, I notice before the work stalls.

The line I drew

Early on, I trusted replies too much. If Claude said "created," I went straight to the next step. The results were not great: a later process built on a file that did not exist surfaced as a different error, and tracing it back cost me extra time.

Now my rule is this: treat the words as a hint, and the file as the fact. Whatever the reply says, I only count a write as done once I have read it back.

If you want a starting point, pick one place in your current workflow where Claude creates a new file, and put verify_written.sh right after it. That is where I started, too.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

◉ Claude.ai2026-10-15
Let Claude Draft the Quote's Wording, Keep the Numbers in Your Own File — A Small Source of Truth and a Check Script
How a freelancer can have Claude polish the wording of quotes and invoices while the amounts stay in a JSON file and get verified by a short Python script.
◉ Claude.ai2026-10-16
I Stopped Asking Claude to 'Cite Sources' — Three Ways I Ask Instead
Three ways I check Claude's answers before they go into a published text, instead of asking for sources: leave room to say 'I don't know', pull verbatim quotes first, and have each claim re-checked against the source after drafting. Plus what still needs a human.
◉ Claude.ai2026-10-09
I Kept Rewriting My First Request to Claude Until I Handed It One Page About My Work
If Claude's answers keep missing the mark, the cause may not be your wording. It may be that you never explained your work. Here is how a non-engineer can write a one-page work description today and fold it into the first request.