Skip to content

AI providers skip reading files before editing due to missing code-level enforcement and inconsistent system prompts #30376

Closed

Description

Code bugs

After checking all source code related to file modifications, these code-level defects cause or allow AI agents to edit files without reading the current content first.

Bug 1: edit.ts claims "will error if not read first" — but never checks

Code: packages/opencode/src/tool/edit.txt:4

This tool will error if you attempt an edit without reading the file.

Code: packages/opencode/src/tool/edit.ts:69-208 (execute function)

The description tells the AI the tool will error. But the actual execute() function:

  • Line 71-77: Only validates filePath and oldString/newString
  • Line 88-168: Reads the file internally via Bom.readFile(), performs the edit, writes back
  • Never checks whether Read tool was called first

Result: The AI can skip Read entirely and call edit directly. It always succeeds. The description is a lie.

Bug 2: write.ts claims "will fail if not read first" — but never checks

Code: packages/opencode/src/tool/write.txt:5

This tool will fail if you did not read the file first.

Code: packages/opencode/src/tool/write.ts:38-101 (execute function)

Same pattern:

  • Line 46-47: Checks if file exists, reads it internally via Bom.readFile() if it does
  • Never checks whether Read tool was called first

Bug 3: apply_patch.ts has zero read-before-edit enforcement

Code: packages/opencode/src/tool/apply_patch.ts:30-304 (execute function)

For "update" hunks (line 106-131) and "delete" hunks (line 161-188), the tool reads the file internally and applies the patch. No read-before-edit check exists. Additionally, apply_patch.txt (33 lines) never mentions reading first.

Compounding factor: packages/opencode/src/tool/registry.ts:329-335 replaces edit/write with apply_patch for non-4, non-oss GPT models. These models lose even the textual claim of read-before-edit enforcement.

Bug 4: instruction.ts tracks read files — but edit/write/apply_patch never use it

Code: packages/opencode/src/session/instruction.ts:15-30

function extract(messages: SessionLegacy.WithParts[]) {
  const paths = new Set<string>()
  for (const msg of messages) {
    for (const part of msg.parts) {
      if (part.type === "tool" && part.tool === "read" && part.state.status === "completed") {
        if (part.state.time.compacted) continue
        const loaded = part.state.metadata?.loaded
        if (!loaded || !Array.isArray(loaded)) continue
        for (const p of loaded) {
          if (typeof p === "string") paths.add(p)
        }
      }
    }
  }
  return paths
}

This function already iterates past messages, finds completed Read tool calls, and tracks which files were read. The result is exported via loaded() at line 233-235.

But this data is ONLY used by instruction.ts:resolve() (line 183) for attaching nearby instruction files. It is never passed to or checked by edit.ts, write.ts, or apply_patch.ts.

This is the fix point: the infrastructure to track read files already exists, but the modification tools don't use it.

Bug 5: Compaction silently destroys read content, making reads unreliable

Code: packages/opencode/src/session/compaction.ts:334-338 (prune function)
When compaction prunes old tool outputs, it sets part.state.time.compacted = Date.now().

Code: packages/opencode/src/session/message-v2.ts:304-305

const outputText = part.state.time.compacted
  ? "[Old tool result content cleared]"
  : truncateToolOutput(...)

Code: packages/opencode/src/session/instruction.ts:20

if (part.state.time.compacted) continue

The sequence:

  1. Model calls Read on a file, gets its content
  2. Context grows, compaction triggers
  3. The Read tool output is replaced with "[Old tool result content cleared]"
  4. instruction.ts:extract() no longer counts this file as read
  5. Model sees the Read call in history but the content is gone
  6. Model edits the file based on stale memory
  7. edit.ts succeeds (no check) but the edit may be wrong

This is a data integrity bug: compaction invalidates the read guarantee without signaling either the model or the editing tools.

Suggested fixes (for maintainers)

  1. Add a Read-before-edit check in edit.ts: before executing, call Instruction.loaded(messages) to verify the target file was read in a recent non-compacted Read call
  2. Same for write.ts when writing to existing files
  3. Same for apply_patch.ts for "update" and "delete" hunks
  4. Add read-before-edit guidance to apply_patch.txt
  5. When compaction clears a Read output, ensure the model gets a signal that re-reading is needed

Environment

OpenCode latest, all platforms

Activity

  1. added
    needs:complianceThis means the issue will auto-close after 2 hours.
    and removed
    needs:complianceThis means the issue will auto-close after 2 hours.
    on Jun 2, 2026
  2. github-actions commented on Jun 2, 2026

    @github-actions
    Contributor

    Thanks for updating the issue! It now meets our contributing guidelines and has been cleared for review.

  3. github-actions commented on Jun 2, 2026

    @github-actions
    Contributor

    Thanks for the detailed write-up — the content is clearly genuine and well-researched. However, this issue still does not use one of the three required issue templates.

    What needs to be fixed:

    This looks like a Feature Request (identifying missing enforcement and proposing a fix). Please:

    1. Edit the issue title to start with [FEATURE]:
    2. Use the Feature Request template structure, which requires:
      • A verification checkbox confirming you've searched for duplicates
      • A description of the problem or need

    Alternatively, if you consider this a Bug Report (existing behavior not matching documented behavior), please use the Bug Report template, which requires a Description field and some context on how to reproduce.

    The three available templates are: Bug Report, Feature Request, and Question. All issues must use one of them.

  4. github-actions commented on Jun 2, 2026

    @github-actions
    Contributor

    Thanks for updating the issue — it now follows the Bug Report template with real content, code references, and reproduction context. The needs:compliance label has been removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions