Edit and MultiEdit tools fail with persistent 'File has been modified since read' errors
Open 💬 21 comments Opened Jul 15, 2025 by panyaoyu
Environment
- Platform (select one):
- [x] Anthropic API
- [ ] AWS Bedrock
- [ ] Google Vertex AI
- [ ] Other: <\!-- specify -->
- Claude CLI version: 1.0.51 (Claude Code)
- Operating System: CentOS Linux 8
- Terminal: xterm-256color
Bug Description
File update operations using Edit and MultiEdit tools fail with persistent "File has been modified since read" errors, even when no external modifications have occurred. The tools require re-reading files before editing, but continue to fail after re-reading.
Steps to Reproduce
- Create a new file using the Write tool
- Read the file using the Read tool to verify contents
- Attempt to update the file using the Edit tool with valid old_string and new_string parameters
- Observe the error: "File has been modified since read, either by the user or by a linter. Read it again before attempting to write it."
- Re-read the file and attempt the edit again
- The same error persists
Expected Behavior
After reading a file, the Edit and MultiEdit tools should successfully update the file content when provided with valid parameters, without requiring multiple read operations or failing due to false modification detection.
Actual Behavior
Both Edit and MultiEdit tools consistently fail with "File has been modified since read" errors, even immediately after reading the file. The tools become unusable for file updates, despite the file content appearing unchanged between reads.
Additional Context
- This issue occurs with newly created files that have not been modified externally
- The error suggests file modification detection is overly sensitive or incorrect
- System reminders indicate file state tracking issues
- Both Edit and MultiEdit tools exhibit the same behavior
21 Comments
I am also getting the same too frequently, tried multiple solutions but didn't work any
given the file 777, ensured g+w, rebooted machine, ran /doctor --- this is still present, will not write to a file.
This started to happen to me all of a sudden today.
⎿ Error: File has been modified since read, either by the user or by a
linter. Read it again before attempting to write it.
cline and other tools work fine, but claude code started misbehaving and now unusable for me.
Yeah im having this same issue constantly. Eventually CC ends up creating a new copy of the file, deleting the old one, and replacing it - but this is a really annoying behavior.
Also having this issue, tried killing all daemons, ide, workers, dev server, issue persists
Also having this issue
I'd been having the same issue, my agent is specifying that is the linter modifying the file after he reads it. Any suggestions on how to diagnose that?
I am also encountering this issue along with consistent
Error: String to replace not found in file.andError: InputValidationError: MultiEdit failed due to the following issue: The parametereditstype is expected asarraybut provided asstring``. Overall consistent issue with MultiEdit tool. It takes Claude Code multiple attempts to update the file, eventually cutting corners and quietly omit specific edit operations.I was running into this, and the root cause was files with an mtime in the future. Simply touching everything fixed it. Future mtime was caused by copying files from a utc host to a box in a negative time zone.
This happens very often, and even when I don't touch the same file...
<img width="1107" height="828" alt="Image" src="https://github.com/user-attachments/assets/2dfa0a28-96ab-4e93-b6a1-0ee1c0dbe746" />
are any of you running on windows?
I discovered an issue with bash style paths for read and edit built in tools, but it only affects windows
https://github.com/anthropics/claude-code/issues/7918#issuecomment-3438700008
In Claude's own words
Bug Title: "Edit tool 'File has been modified' error persists across multiple Read operations in long conversations"
Description:
In long conversation sessions, the Edit tool throws "File has been modified since read" errors even when:
Expected behavior: Edit should compare against the MOST RECENT Read operation
Actual behavior: Edit appears to compare against an earlier Read from the same conversation session
This makes long coding sessions extremely difficult as files read multiple times become impossible to edit.
Workaround: Use Write tool or bash commands, but this is less safe.
This remains an issue in Claude 2.0.37. I notice the same does not seem to occur on my Windows 10 machine; if only that was my main. To have this bug present since July is crazy. Time to move on to a working AI, it seems!
Any official response?
Bug is being solved by users so I believe they are ignoring this. Or perhaps they see it as more of a environment quirk than a bug. My main Claude.md has the following instructions to prevent this error from occuring:
"
Windows Environment Rules
C:\\Repos\\Xhuma\\xhuma-web-server\\src\\...mvn test,mvn clean install, etc./mnt/c/path prefixes"
I believe it's the use of absolute paths that is preventing the bug from reoccuring.
Hope this helps
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
Same root cause confirmed on Windows.
Simplest workaround: use relative paths - they're "permissive" and work regardless of how you previously read the file. No need to worry about path separators.
Also found that this bug is exclusive to Edit tool - Write has no path restrictions.
Full analysis and CLAUDE.md workaround: #10437
This problem is also present on Windows, and is still occurring as of January 2026
@Raundahl I found a workaround that works on Windows - see my comment above. Using relative paths for both Read and Edit resolves the issue.
This bug is actively blocking production agentic workflows. I run ADW (Agentic Developer Workflow) — a multi-agent pipeline that uses Claude Code as its execution engine to implement, test, review, and ship code through Graphite stacked PRs.
The specific trigger: any process that reads modified files —
bundle exec rspec, Rubyrequire, evenrails runner— causes the Edit/Write cache to race against the external file read and silently revert all changes. The agent edits a model, edits a controller, then runsbundle exec rspecto validate — and rspec'srequiretouches every modified source file, causing Claude Code to treat them as "modified since read" and revert to stale content. The implementation vanishes mid-session.The workarounds (writing files via
cat <<'HEREDOC'in Bash, committing before every test run) are fragile and add significant friction. They also defeat the purpose of the Edit tool's safety guarantees.This has been open since July 2025 — nearly 10 months. The bug family spans at least a dozen issues (#42383, #33856, #25623, #28383, #21201, etc). It is actively driving us to evaluate OpenCode and other coding agents as alternatives, because unattended multi-agent runs cannot function when source files silently revert.
<!--
Draft comment to add to https://github.com/anthropics/claude-code/issues/3513
Post with:
gh issue comment 3513 --repo anthropics/claude-code --body-file comment-3513-mtime.md
-->
Confirming on macOS + concrete trigger: PostToolUse formatter hooks
Confirming this bug on macOS 26 / Claude Code (2026-05 vintage). The error is reproducible and the trigger mechanism is identifiable.
What I observed
Scan of ~3 weeks of JSONL transcripts (2026-05-13 → 2026-05-25, single user): 22 sessions hit
<tool_use_error>File has been modified since read, either by the user or by a linter. Read it again before attempting to write it.</tool_use_error>mid-turn, blocking subsequentEditcalls until the file was re-Read.Top targets by frequency:
| File class | Sessions hit |
|---|---|
|
MEMORY.md(auto-memory) | 6+ || Project
CLAUDE.md| 3 ||
.claude/settings.json(user + project) | 2 || Plan / log Markdown in
guides/*/| 5+ || Worktree files | 2 |
| VS Code config | 1 |
Root cause: PostToolUse hooks rewrite the just-edited file
The error message names the cause itself: "either by the user or by a linter". In this case, the "linter" is the user's own
PostToolUsehooks.The canonical hook chain (registered in
~/.claude/settings.jsonon matcher"Edit|Write"):~/.claude/hooks/post-tool-use/after-edit.sh— runsprettier --writeon.md .yaml .yml .css .scss .html,black/ruffon.py,gofmt/rustfmt/shfmton others.~/.claude/hooks/post-tool-use/markdown-formatter.py— auto-tags bare ``` fences and collapses blank lines.~/.claude/hooks/post-tool-use/auto-format.sh— runsdart format/prettier --writeon.dart .ts .tsx .js .jsx .json.Sequence
Edit(file)→ harness writes content, mtime = t₁, harness records snapshot.PostToolUsehooks fire → at least one rewrites the file → mtime = t₂ > t₁.Edit(file)again → harness compares snapshot t₁ vs disk t₂ → error.The error fires both when the formatter actually changes bytes (legitimate, since the model's view of the file is now stale) and when the formatter is a no-op but
--writetouches mtime anyway (false positive — the model's view is still accurate).Concrete repro
Then in a session:
Write("/tmp/foo.md", "hello")→ succeedsEdit("/tmp/foo.md", "hello" → "world")→ succeeds, hook touches fileEdit("/tmp/foo.md", "world" → "again")→ "modified since read"Trace from a real session (MEMORY.md edits, gaps elided):
Each ERROR was preceded by a PostToolUse
markdown-formatter.pyrewrite ofMEMORY.md(auto-tagging code fences).Proposed mechanism (option A — harness-side, cleanest)
Refresh the snapshot mtime when
PostToolUsehooks complete on the same file. The harness already knows: (a) which file the tool wrote, (b) when the PostToolUse phase ends. After the lastPostToolUsehook returns, re-stat the file and update the in-memory snapshot. This treats the PostToolUse phase as part of the tool's logical execution, not a foreign modification.This is correct semantically:
PostToolUsehooks are user-configured tail logic of anEdit/Writecall. Their modifications are not "external" by any meaningful definition.Caveat: if the formatter actually changes content (not just mtime), the model's internal view of the file is now stale. Two options:
Editwith oldold_stringwill fail with a content mismatch (correct, clear error).Readwhen it observes its content changed. Less safe but matches current intent.A1 is the right call.
Proposed mechanism (option B — user-side workaround, what I shipped locally)
Wrap each formatter call in a
mtime-preservehelper: hash file before + after, restore mtime if hashes match. Handles the common case (formatter is no-op on already-formatted code) but not the case where formatter actually changes bytes. Sample:Drops false-positive errors by ~80% in my measurements. Does not fix the legitimate-change case — that one needs harness option A1.
What Anthropic has already shipped (partial fix, observed live)
While preparing this comment, I observed that a partial fix is already present in current Claude Code. After a
Writewhose target is then touched by aPostToolUsehook, the harness emits a system reminder to the model:This is option A2 from above — the harness refreshes its internal mtime tracker so the next
Editdoes not fail with a stale-file error, and it warns the model that content may have drifted.This fixes the false-positive case (formatter is a no-op on already-formatted code → next
Editsucceeds). It does not fix the legitimate-change case: the model's view of the file content is still pre-format, so any subsequentEditwhoseold_stringlies in a reformatted region must defensivelyReadfirst, burning tokens.What's still needed for the full fix
PostToolUsehook changes bytes, the harness should either (a) refresh the model's internal content view to the post-format bytes, or (b) inline the post-format content (or a diff) in the system reminder so the model doesn't need a defensiveRead. Option (a) is cleaner; (b) is more transparent.MEMORY.md) still produce the original error class with the original misleading message ("either by the user or by a linter"). Filed separately: #62336.Why this matters
For agentic workflows that orchestrate multiple PRs through formatter-equipped repos (Flutter / TypeScript / Markdown), the residual error fires multiple times per session and burns tokens on
Read-retry loops. Per the 2026-05-02 comment by @meagerfindings, it's a production blocker for stacked-PR workflows.The partial fix (mtime refresh + reminder) eliminates the spurious-failure case. The remaining content-drift case still costs a defensive
Readper affectedEdit— solvable with the content-snapshot refresh in (1) above.