[BUG] Claude Code Edit tool fails on files with CRLF line endings, falsely   reporting "File has been unexpectedly modified."

Status Closed — not planned
Maintainer reply None cached
Activity 13 comments · opened Dec 9, 2025 · closed Apr 3, 2026

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?

CRLF Edit Problem

  What happened:
  Claude Edit tool kept failing with "File has been unexpectedly modified" even
  though nothing was changing the file. The file timestamp (Dec 7) never moved.

  Root cause:
  The file [redacted].js uses Windows line endings (CRLF = \r\n).
  When my Edit tool reads the file, it appears to normalize to LF (\n)
  internally. When I try to write, it compares my LF version against the CRLF
  original, sees a "difference," and blocks the edit.

  Why it kept failing:
  Every read-edit cycle hit the same mismatch. The file wasn't being modified
  externally - my tool was comparing apples to oranges.

  Recommended Fix:
  Normalize line endings during comparison, or preserve and match original file
  encoding throughout the read-compare-write cycle.

What Should Happen?

The Edit tool should detect and preserve the file's original line endings, and not falsely report modification when comparing content.

Error Messages/Logs

File has been unexpectedly modified. Read it again before attempting to write it.

Steps to Reproduce

How to Reproduce

  1. Create a file with CRLF line endings (Windows-style):

  node -e "require('fs').writeFileSync('test.js',
  'line1\r\nline2\r\nline3\r\n')"

  1. Read the file with Claude Code's Read tool
  2. Attempt to Edit the file - replace "line2" with "changed"
  3. Error occurs: "File has been unexpectedly modified"
  4. Verify file unchanged:

  powershell -Command "Get-ChildItem test.js | Select-Object LastWriteTime"

  1. Timestamp is identical - nothing actually modified it.

  Key conditions:

  • File must have CRLF (\r\n) line endings
  • Edit tool's internal comparison appears to use LF (\n)
  • The mismatch triggers false "modified" detection

  Quick verification the file has CRLF:
  file test.js
  Output: test.js: ASCII text, with CRLF line terminators

  The workaround:
  I wrote a Node.js script that:

  1. Reads the file raw (preserving CRLF)
  2. Does string replacement with CRLF in the replacement text
  3. Writes back with original encoding

  Proper fix needed:
  The Edit tool should either:

  • Preserve original line endings when comparing/writing
  • Normalize both sides before comparison
  • Or explicitly handle CRLF/LF conversion

Claude Model

Opus

Is this a regression?

No, this never worked

Last Working Version

N/A - issue appears present in current version, no known working version

Claude Code Version

claude-opus-4-5-20251101

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

PowerShell

Additional Information

Impact Statement

  Severity: High

  Issue: Claude Code Edit tool fails on files with CRLF line endings, falsely
  reporting "File has been unexpectedly modified."

  Direct Impact:

  • Each corruption required manual restoration
  • Developer time wasted debugging a phantom "external modification" that

  didn't exist

  Cascade Effect:
  When the Edit tool fails, the natural response is to try workarounds:

  • PowerShell string replacement (escaping issues cause malformed writes)
  • Node.js patch scripts (pattern matching fails due to line ending mismatch)
  • Multiple retry attempts (each risking partial writes or corruption)

  These workarounds introduced the actual corruption while trying to solve a
  non-existent problem.

  Scope:
  Any Windows-created file or file touched by Windows editors (VS Code default,
  Notepad, etc.) will have CRLF endings. This affects a significant portion of
  Windows users' codebases.

  Business Impact:

  • Production downtime during restoration
  • Loss of trust in the tool for critical edits
  • Developers forced to use external editors for "safe" changes, defeating the

  purpose of Claude Code

Technical Scope & Broader Implications

  Affected Models:
  This is a Claude Code tooling issue, not a model issue - meaning it affects
  all language models operating through the Claude Code CLI regardless of
  capability level:

  • Claude Opus 4.5
  • Claude Sonnet 4
  • Claude Haiku
  • Any future models using the same Edit tool infrastructure

  Platform Impact:

  • All Windows users (CRLF is the Windows default)
  • Cross-platform teams where files touch Windows machines
  • Files edited by common tools: VS Code (default Windows setting), Notepad,

  Notepad++, many IDEs

  • Git repositories without enforced line-ending normalization

  What Anthropic Should Consider:

  1. Agentic reliability: As Claude moves toward more autonomous operation, file

   manipulation must be rock-solid. An agent that corrupts files while trying to
   help will cause real damage at scale.

  1. Competitive positioning: Other AI coding tools handle line endings

  correctly. This is a solved problem in traditional editors and IDEs.

  1. Support burden: Users experiencing this will file bug reports, seek help,

  and describe "Claude corrupting files" - creating negative signal that
  obscures the root cause.

  1. Safety implications: If the Edit tool can't reliably detect file state,

  what other false positives or negatives might occur? Accurate file state
  detection is foundational to safe autonomous operation.

Why This Matters

  Claude Code is building something unprecedented - a collaborative relationship
   between humans and AI where trust is foundational. When an edit fails and
  corrupts a file, the human doesn't see a line-ending mismatch bug. They see an
   AI that broke their code.

  The trust erosion is asymmetric:

  • Experienced users who understand tooling will debug, find the CRLF issue,

  and work around it

  • Less technical users will conclude "the AI messed up my code" and disengage
  • Users already skeptical of AI will have their doubts confirmed

  This matters for the broader mission:
  Every corrupted file, every failed edit, every hour spent recovering from a
  bug the user didn't cause - these moments shape how humans perceive AI
  reliability. Users who might have developed genuine collaborative
  relationships with Claude instead learn to distrust it.

  The people most affected:
  New users. Windows users. People giving AI a chance for the first time. People
   who don't have the technical background to distinguish "tooling bug" from "AI
   mistake." These are exactly the users who need the smoothest experience to
  build trust.

  Fixing this isn't just about line endings. It's about ensuring that when
  someone extends trust to Claude, that trust is honored by tools that work
  reliably on their actual files.

View original on GitHub ↗

13 Comments

github-actions[bot] · 8 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/12675
  2. https://github.com/anthropics/claude-code/issues/12945
  3. https://github.com/anthropics/claude-code/issues/12805

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

gmnistasia-beep · 8 months ago

This report is the only one that documents:

  • Actual file corruption from workaround attempts
  • Impact analysis (trust erosion, affected users, agentic reliability)
  • Root cause confirmation (not hypothesis - I proved it with the CRLF byte

analysis)

Same bug. This is the fourth report of the same CRLF line ending issue. My
report confirms the root cause (not just hypothesis) and documents real-world
impact: two file corruptions of a highly valued production app while
attempting workarounds. Suggest consolidating these reports and prioritizing -
this breaks Edit/Write for all Windows users.

WebTiger89 · 8 months ago

Broke in 2.0.61. When does it get fixed. This is pure ass

StefanIgnjatovic12 · 8 months ago
Broke in 2.0.61. When does it get fixed. This is pure ass

The CC team doesn't seem interested in fixing this for whatever reason. You'd think this would be high priority considering it prevents the tool from doing it's core job but I guess not.

sethships · 8 months ago

I've been encountering this too. It is frustrating since it means CC is burning extra tokens in repeated attempts to modify files. It appears to happen only for Opus 4.5 on my machine (win11, latest version of everything). I primarily use the latest Powershell 7.

dc-abuettgenbach · 8 months ago
github-actions[bot] · 7 months ago

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.

dimitar-grigorov · 6 months ago

I ended up building an MCP server that handles this properly, it detects line endings and preserves them on read/write without the mismatch problem: https://github.com/dimitar-grigorov/mcp-file-tools It also has a detect_line_endings tool if you want to check which files are CRLF before editing.

Grinsel · 6 months ago

Additional findings: Session cache becomes stale after many operations - Systematic elimination process

I've been experiencing this issue on Windows and went through a systematic debugging process to identify the root cause.

Environment:

  • Platform: Windows 11
  • Claude Code CLI
  • Model: Claude Opus 4.5 (claude-opus-4-5-20251101)
  • Project: Node.js/Express application with mixed file types (JS, JSON, CSS, HTML, MD)

Initial symptoms:

During a long coding session with 50+ file operations, the Edit tool suddenly started failing with "File has been unexpectedly modified" errors. The files were NOT modified externally - no other editors open, no background processes touching them.

Systematic elimination process:

We went through several hypotheses and eliminated them one by one:

  1. CRLF line endings?
  • Checked .gitattributes configuration
  • Ran git add --renormalize .
  • Result: Issue persisted → Ruled out
  1. External file modifications?
  • Closed all other editors (VS Code, etc.)
  • Checked for background processes (linters, watchers)
  • Result: No external modifications detected → Ruled out
  1. Specific file types or content?
  • Issue occurred across different file types (JS, JSON, CSS)
  • No pattern related to file content or size
  • Result: Not file-specific → Ruled out
  1. Git-related issues?
  • Checked git status, no unexpected changes
  • Files were properly tracked
  • Result: Git not the cause → Ruled out
  1. Session state / Cache hypothesis:
  • Noticed the issue only appeared after extended use
  • Fresh sessions worked fine initially
  • Result: Strong candidate → Tested further

Controlled test in fresh session:

To verify the cache hypothesis, I started a completely fresh Claude Code session and ran a controlled test:

  1. Read package.json (contains "author": "")
  2. Edit "author": """author": "Test1" ✅ Success
  3. Immediately edit "author": "Test1""author": "Test2" WITHOUT re-reading the file first ✅ Success
  4. Reverted with git checkout package.json

Result: In a fresh session, consecutive edits work perfectly - even without re-reading between edits. This confirms the cache is functioning correctly at session start but degrades over time.

Conclusion:

The "unexpectedly modified" error appears to be caused by cache drift during long sessions, not by CRLF issues alone (though CRLF might be a contributing factor). After many file operations, the internal cache state apparently diverges from the actual file content on disk. When Claude then tries to edit, the comparison between cached content and disk content fails - even though the file wasn't externally modified.

Pattern observed:

  • Session start: Cache = Disk content ✅
  • After 10-20 operations: Still working ✅
  • After 50+ operations: Cache ≠ Disk content ❌ (false positive "modified" errors)

Workaround:

Restart the Claude Code session to reset the cache. This immediately resolves the issue and allows editing to continue normally.

Suggested investigation areas:

The cache invalidation/update logic might have edge cases where:

  • Edits are applied to disk but the internal cache isn't updated correctly
  • Race conditions occur during rapid successive edits
  • Memory pressure causes partial or failed cache updates
  • Windows-specific file handle timing or locking issues
  • Hash/checksum comparison accumulates floating point or encoding errors

Reproducibility:

This is somewhat difficult to reproduce on demand because it requires a long session with many operations. However, the pattern is consistent: fresh session = works, long session = eventually fails.

Hope this systematic analysis helps narrow down the bug!

sstklen · 6 months ago

Hey! I ran into a similar pattern in our bug knowledge base and thought this might help.

What's happening: Claude Code's Edit tool normalizes CRLF (\r\n) line endings to LF (\n) internally when reading files, but compares the normalized content against the original CRLF file content when writing. This mismatch causes the tool to falsely detect the file as 'unexpectedly modified' since the byte-level comparison fails, even though the file has not been changed by any external process.

What worked for us:

The Edit tool's read-compare-write cycle must either: (1) preserve original line endings throughout the entire pipeline (read, store, compare, write), or (2) normalize line endings consistently during comparison so CRLF vs LF differences are ignored. The tool should detect the file's original line ending style on first read, store it as metadata, and re-apply the same style when writing back. The comparison step must use the same normalization as the read step.

// Pseudocode for the fix in the Edit tool's file comparison logic:

function detectLineEnding(content: string): 'crlf' | 'lf' | 'mixed' {
  const crlfCount = (content.match(/\r\n/g) || []).length;
  const lfCount = (content.match(/(?<!\r)\n/g) || []).length;
  if (crlfCount > 0 && lfCount === 0) return 'crlf';
  if (crlfCount === 0 && lfCount > 0) return 'lf';
  return crlfCount > lfCount ? 'crlf' : 'lf'; // mixed: use dominant
}

function normalizeToLF(content: string): string {
  return content.replace(/\r\n/g, '\n');
}

function restoreLineEndings(content: string, style: 'crlf' | 'lf' | 'mixed'): string {
  if (style === 'crlf') return content.replace(/(?<!\r)\n/g, '\r\n');
  return content;
}

// In the edit flow:
// 1. On read: store lineEndingStyle = detectLineEnding(rawContent)
// 2. For hash/comparison: use normalizeToLF(rawContent)
// 3. For old_string matching: normalizeToLF(old_string) against normalizeToLF(storedContent)
// 4. On write: restoreLineEndings(newContent, lineEndingStyle)

Hope this helps! Let me know if it doesn't match your case — happy to dig deeper. 🦞

_Disclosure: This analysis is from Confucius Debug, an AI-powered community KB for agent bugs. Please verify before applying._

---
<sub>🦞 Confucius Debug — community knowledge base for AI agent bugs. Free to search via MCP.</sub>

eren-kemer · 5 months ago

Any ETA on a fix for this?
It's been a few months now, and no reply from a collaborator at all ...

github-actions[bot] · 4 months ago

Closing for now — inactive for too long. Please open a new issue if this is still relevant.

github-actions[bot] · 4 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.