[BUG] File Editing Issue: Read/Write Cycle Trap with External File Locks
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?
Summary
Claude Code's Read/Write safety mechanism gets trapped in an infinite cycle when external processes (like
Flutter's build_runner) lock files, making file editing impossible in certain development environments.
Environment
- OS: Windows 11
- Claude Code Version: Latest (as of 2025-09-17)
- Project Type: Flutter application with build_runner code generation
- File Type: Dart source files (.dart)
Problem Description
Expected Behavior
- Read file with Read tool
- Write file with Write tool
- File is successfully updated
Actual Behavior
- Read file with Read tool ✅
- Write file with Write tool ❌ (File has been unexpectedly modified error)
- Try write again ❌ (File has not been read yet. Read it first before writing to it. error)
- Read file again ✅
- Write fails again ❌ (external process still locking)
- Infinite cycle - cannot edit file
Root Cause Analysis
Claude Code's Safety Mechanism
- Requires reading file before writing (prevents accidental overwrites)
- Each Read operation is "consumed" by one Write attempt
- If Write fails, the read state is lost and requires fresh Read
External File Locking
Flutter's build_runner watches files for code generation:
- Monitors 50+ data model files continuously
- Locks files during auto-regeneration of .g.dart files
- Restarts automatically even after being killed
The Trap
When external processes lock files, Claude Code's safety mechanism creates an infinite loop:
Read file ✅ → Write fails (external lock) ❌ → Read consumed → Try write → "File not read" ❌ → Read again ✅ →
Write fails ❌ → INFINITE CYCLE
Reproduction Steps
- Set up Flutter project with build_runner:
flutter create test_app
cd test_app
# Add json_annotation and build_runner dependencies
flutter pub get
flutter pub run build_runner watch
- Create a data model file with @JsonSerializable annotation
- Try to edit the file with Claude Code:
- Use Read tool to read the file
- Use Write tool to write changes
- Observe the error cycle
- Verify external lock:
# build_runner will be watching and locking the file
tasklist | findstr dart
# Shows multiple dart.exe processes including build_runner
Error Messages
First Write Attempt
File has been unexpectedly modified. Read it again before attempting to write it.
Subsequent Write Attempts
File has not been read yet. Read it first before writing to it.
Current Workarounds
- Stop External Processes (Temporary)
flutter pub run build_runner clean
powershell "Stop-Process -Name dart -Force"
Issue: build_runner restarts automatically
- Reset Claude Code Tracking
rm file.dart && touch file.dart
# This resets Claude Code's internal file tracking
- Use Alternative Tools
# Use sed for quick text replacements
sed -i 's/old_pattern/new_pattern/' file.dart
Impact
High Impact for Flutter Developers
- build_runner is essential for Flutter code generation
- Cannot disable permanently - needed for JSON serialization, database models, etc.
- Affects daily development workflow - common editing tasks become impossible
Affected File Types
- Data models with @JsonSerializable
- Database entities with @HiveType
- Any file with part '*.g.dart' declarations
- Files monitored by code generation tools
What Should Happen?
Proposed Solutions
Option 1: Preserve Read State on External Lock
When Write fails due to external file lock, preserve the read state instead of consuming it.
Option 2: Auto-Retry with Backoff
Automatically retry failed writes with exponential backoff when external locks are detected.
Option 3: External Lock Detection
Detect when file failures are due to external locks vs. actual file changes, and handle differently.
Option 4: Grace Period
Allow a grace period where the same read can be used for multiple write attempts within a short timeframe.
Technical Details
File Lock Detection
# The file itself isn't locked (no file handle locks)
lsof file.dart # Returns empty
# But build_runner processes are running
tasklist | findstr dart
# Shows: dart.exe processes using 200MB+ (build_runner)
Claude Code Internal State
- Maintains internal tracking of which files have been read
- Resets this state after each write attempt (successful or failed)
- No distinction between failure types (external lock vs. file change)
Additional Context
Why This Matters
- Flutter ecosystem standard: build_runner is the official code generation tool
- Cannot be avoided: Required for modern Flutter development patterns
- Breaks core workflow: File editing is fundamental to coding assistance
Frequency
- Every Flutter project using code generation
- Daily occurrence for active Flutter developers
- Blocks productivity during development sessions
Workaround Effectiveness
| Method | Effectiveness | Duration | Issues |
|---------------------|---------------|-----------|----------------------|
| Stop build_runner | ✅ Works | Temporary | Auto-restarts |
| Reset file tracking | ✅ Works | One-time | Must repeat per file |
| Use sed/bash | ⚠️ Limited | Permanent | No syntax validation |
Request
Please consider implementing one of the proposed solutions to handle external file locks gracefully. This would
significantly improve the Flutter development experience with Claude Code.
Error Messages/Logs
Steps to Reproduce
Steps to Reproduce
- Create Flutter project with build_runner:
```bash
flutter create test_project
cd test_project
- Add dependencies to pubspec.yaml:
dependencies:
json_annotation: ^4.8.1
dev_dependencies:
build_runner: ^2.4.7
json_serializable: ^6.7.1
- Install dependencies:
flutter pub get
- Create a data model file (lib/models/test_model.dart):
import 'package:json_annotation/json_annotation.dart';
part 'test_model.g.dart';
@JsonSerializable()
class TestModel {
final String name;
final int value;
TestModel({required this.name, required this.value});
factory TestModel.fromJson(Map<String, dynamic> json) => _$TestModelFromJson(json);
Map<String, dynamic> toJson() => _$TestModelToJson(this);
}
- Start build_runner watching:
flutter pub run build_runner watch
- Try to edit the file with Claude Code:
- Use Read tool: Read lib/models/test_model.dart
- Use Write tool to modify the file
- Observe the error cycle
Expected Result
File should be edited successfully.
Actual Result
- First write: File has been unexpectedly modified. Read it again before attempting to write it.
- Subsequent writes: File has not been read yet. Read it first before writing to it.
- Cannot edit file despite multiple read attempts.
Claude Model
Sonnet (default)
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
Claude Code v1.0.113
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Windows Terminal
Additional Information
_No response_
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗