[Tracking] Edit tool reliability: "modified since last read" errors (Undo/Redo & Persistence) #3693

Open
opened 2026-02-16 17:41:07 -05:00 by yindo · 2 comments
Owner

Originally created by @AdiY00 on GitHub (Dec 20, 2025).

Originally assigned to: @thdxr on GitHub.

Note: This is a tracking issue to make the Edit tool more reliable. It covers the immediate fixes we're working on and a plan for the long-term solution.

Related PRs & Issues

The Problem

The Edit tool frequently rejects valid operations with the error File [...] has been modified since it was last read in two common scenarios:

  1. Undo/Redo: When reverting a chat to a previous state using /undo or the UI.
  2. Session Persistence: When reopening a session after a restart or reloading the window.

In both cases, the model often has the correct context (either restored from history or "remembered" from the session), but the internal safety check fails, forcing redundant Read calls and wasting valid Edit calls (which can be expansive and take a long time for big edits).

Root Cause

The current FileTime implementation relies on in-memory timestamps (Date) compared against the filesystem's mtime.

  • Undo/Redo: Reverting files via git snapshots updates their mtime on disk, making them appear "newer" than the last time the model read them, even if the content is exactly what the model expects.
  • Persistence: The FileTime state is stored in memory (Instance.state). When the server restarts, this state is lost, so any subsequent edit attempts fail until the file is read again.

Proposed Solutions

1. Immediate Fixes

Two separate PRs address the immediate pain points:

A. Fix for Undo/Redo (PR #4923)

This PR manually updates the FileTime entry for affected files whenever a revert or unrevert operation occurs.

  • Pros: Solves the immediate friction for undo/redo.
  • Cons: It blindly trusts that the model has read the file in the context we are reverting to. If we revert to a point before the file was read, this allows an edit without a read. However, this is a much rarer scenario (since most models reliably use the read tool if they haven't seen the file before). Even though it IS a risk, it's still way better than the current state.

B. Fix for Session Persistence (PR #5045)

This PR persists the FileTime state to disk using the Storage module.

  • Mechanism: Writes timestamps to ["filetime", sessionID, encodedPath] so the "last read" time survives server restarts.
  • Pros: Prevents unnecessary re-reads after reloading the window or restarting the server.

2. Long-term Solution (Persisted Content Hashing)

A more robust architecture would replace or augment the timestamp check with context-aware content hashing.

  • Mechanism: Maintain a map of filePath -> contentHash linked to the session history.
  • Persistence: Store this map using the Storage module (similar to PR #5045) so it survives restarts.
  • Context Awareness: When performing an undo, the system would restore the hash map to its state at that point in history.
  • Verification: The Edit tool would check if the current on-disk hash matches the "expected" hash from the session state. If they match, the edit proceeds regardless of the timestamp.

Discussion

I'm down to implement the hashing solution, but I wanted to sanity check the direction first.

  • Persistence Strategy: Should follow the pattern from PR #5045? We can use a similar structure for hashes: ["filehash", sessionID, encodedPath].
  • Verification Logic: Should we keep FileTime as the primary check and add hashing as a fallback? This aligns with the suggestion in #3681.

OpenCode version

No response

Steps to reproduce

No response

Screenshot and/or share link

No response

Operating System

No response

Terminal

No response

Originally created by @AdiY00 on GitHub (Dec 20, 2025). Originally assigned to: @thdxr on GitHub. > **Note:** This is a tracking issue to make the `Edit` tool more reliable. It covers the immediate fixes we're working on and a plan for the long-term solution. ## Related PRs & Issues - **Undo/Redo Fix:** #4923 - **Persistence Fix:** #5045 - **Hashing Discussion:** #3681 ## The Problem The `Edit` tool frequently rejects valid operations with the error `File [...] has been modified since it was last read` in two common scenarios: 1. **Undo/Redo:** When reverting a chat to a previous state using `/undo` or the UI. 2. **Session Persistence:** When reopening a session after a restart or reloading the window. In both cases, the model often has the correct context (either restored from history or "remembered" from the session), but the internal safety check fails, forcing redundant `Read` calls and wasting valid `Edit` calls (which can be expansive and take a long time for big edits). ## Root Cause The current `FileTime` implementation relies on in-memory timestamps (`Date`) compared against the filesystem's `mtime`. - **Undo/Redo:** Reverting files via git snapshots updates their `mtime` on disk, making them appear "newer" than the last time the model read them, even if the content is exactly what the model expects. - **Persistence:** The `FileTime` state is stored in memory (`Instance.state`). When the server restarts, this state is lost, so any subsequent edit attempts fail until the file is read again. ## Proposed Solutions ### 1. Immediate Fixes Two separate PRs address the immediate pain points: #### A. Fix for Undo/Redo (PR #4923) This PR manually updates the `FileTime` entry for affected files whenever a `revert` or `unrevert` operation occurs. - **Pros:** Solves the immediate friction for undo/redo. - **Cons:** It blindly trusts that the model has read the file in the context we are reverting to. If we revert to a point _before_ the file was read, this allows an edit without a read. However, this is a much rarer scenario (since most models reliably use the read tool if they haven't seen the file before). Even though it IS a risk, it's still way better than the current state. #### B. Fix for Session Persistence (PR #5045) This PR persists the `FileTime` state to disk using the `Storage` module. - **Mechanism:** Writes timestamps to `["filetime", sessionID, encodedPath]` so the "last read" time survives server restarts. - **Pros:** Prevents unnecessary re-reads after reloading the window or restarting the server. ### 2. Long-term Solution (Persisted Content Hashing) A more robust architecture would replace or augment the timestamp check with context-aware content hashing. - **Mechanism:** Maintain a map of `filePath -> contentHash` linked to the session history. - **Persistence:** Store this map using the `Storage` module (similar to PR #5045) so it survives restarts. - **Context Awareness:** When performing an `undo`, the system would restore the hash map to its state at that point in history. - **Verification:** The `Edit` tool would check if the current on-disk hash matches the "expected" hash from the session state. If they match, the edit proceeds regardless of the timestamp. ## Discussion I'm down to implement the hashing solution, but I wanted to sanity check the direction first. - **Persistence Strategy:** Should follow the pattern from PR #5045? We can use a similar structure for hashes: `["filehash", sessionID, encodedPath]`. - **Verification Logic:** Should we keep `FileTime` as the primary check and add hashing as a fallback? This aligns with the suggestion in #3681. ### OpenCode version _No response_ ### Steps to reproduce _No response_ ### Screenshot and/or share link _No response_ ### Operating System _No response_ ### Terminal _No response_
yindo added the bug label 2026-02-16 17:41:07 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Dec 20, 2025):

This issue might be a duplicate of existing issues. Please check:

  • #4704: /undo and /timeline undo does not revert file edits
  • #4548: /undo does not update Modified Files list
  • #5474: /undo command only rolls back AI conversation message, not the associated file changes
  • #2379: /undo is broken when you re-open opencode
  • #3681: Compare files by Hash as fallback before marking them as 'Must be Read Again' on Edits if Timestamp Doesn't Match

Feel free to ignore if none of these address your specific case.

@github-actions[bot] commented on GitHub (Dec 20, 2025): This issue might be a duplicate of existing issues. Please check: - #4704: /undo and /timeline undo does not revert file edits - #4548: /undo does not update Modified Files list - #5474: /undo command only rolls back AI conversation message, not the associated file changes - #2379: /undo is broken when you re-open opencode - #3681: Compare files by Hash as fallback before marking them as 'Must be Read Again' on Edits if Timestamp Doesn't Match Feel free to ignore if none of these address your specific case.
Author
Owner

@AdiY00 commented on GitHub (Dec 20, 2025):

(the first 4 are unrelated and the last one is mentioned in this issue)

@AdiY00 commented on GitHub (Dec 20, 2025): (the first 4 are unrelated and the last one is mentioned in this issue)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#3693