Skip to content

The edit tool intermittently reports "Could not find oldString" for text that is verifiably present in the target file #52067

Closed as not planned

Description

@danse

Description

Summary

The edit tool intermittently reports "Could not find oldString" for text that is verifiably present in the target file, and separately reports genuinely different oldString/newString pairs as identical when they differ only in leading whitespace. Both block file editing and force workarounds.

Environment

  • opencode version: v2.0.16
  • OS: Linux grimorio 6.8.0-142-generic (linux x86_64), Ubuntu 24.04
  • Terminal: TERM=xterm-256color, COLORTERM=truecolor, TERM_PROGRAM unset
  • Shell: /bin/bash
  • Install/channel: latest
  • Active plugins: none found in config

Reproduction

Three independent failures, all observed in a single session while editing Python and Markdown files.

1. Whitespace-only difference reported as identical

edit(
    path="tests/test_cli.py",
    oldString='rewrites nothing that was said."""',
    newString='    rewrites nothing that was said."""',
)

Expected: the 4 leading spaces inserted.

Actual:

Error: No changes to apply: oldString and newString are identical.

The two arguments are not identical. The tool appears to trim or otherwise normalize whitespace before comparing them, so a legitimate indentation-only edit is discarded.

2. oldString not found, byte-for-byte present

edit(
    path="agenda.md",
    oldString="## Not decided\n",
    newString="## Not decided\n\n- **New item.** ...\n",
)

grep -n "Not decided" agenda.md returned 48:## Not decided, and the line is exactly ## Not decided with no trailing content.

Actual:

Error: Could not find oldString in /home/marea/hub/acciughe/agenda.md.

Re-issuing the identical call with the trailing newline removed from oldString succeeded against the same file, unchanged.

3. Multi-line oldString ending in """ not found

edit(
    path="src/acciughe/model.py",
    oldString='    about again.\n    """',
    newString='    about again.\n\n    The model is asked ...\n    """',
)

The target text was confirmed present by reading the file at the reported line numbers.

Actual:

Error: Could not find oldString in /home/marea/hub/acciughe/model.py.

The same edit succeeded after re-reading the file and re-anchoring the oldString on different, longer surrounding text.

Steps common to all three

  1. Read a file to locate the exact text.
  2. Call edit with an oldString taken verbatim from that read.
  3. Receive a mismatch error.
  4. Confirm with read and/or grep that the text is present and unmodified.
  5. Re-anchor on a longer or shorter span, or split the edit — it then succeeds against an unchanged file.

Expected Behavior

edit matches oldString against the file contents as given. When it cannot find it, the reported reason is accurate. When oldString and newString differ, the edit is applied.

Actual Behavior

  • Case 1: a whitespace-only edit is rejected as a no-op.
  • Cases 2 and 3: a verbatim oldString is reported absent from a file where it is present. Re-anchoring succeeds with no intervening change to the file.

Pattern worth investigating: failures 1 and 3 both involve """ in newString, and case 2 differs from its working variant only by a trailing \n. This suggests quote escaping and/or trailing-whitespace handling in the argument layer rather than a genuine mismatch.

Additional Context

  • Frequency: intermittent, roughly 6 failures across ~150 tool calls in one session. Every failure was recoverable by re-reading the file and re-anchoring, but it reliably consumed an extra round trip and, in a long editing sequence, repeatedly stalled progress.
  • Impact: highest on long edits where oldString is a full function or docstring block — exactly the case where a long anchor is worth using. The failure pushes the agent toward progressively shorter anchors, which is the opposite of what makes edits safe.
  • Workarounds tried, all of which helped: re-read the file immediately before retrying; shorten oldString to a smaller unique span; split one large edit into several small ones; anchor on text that avoids """ sequences.
  • Workarounds that were unavailable by policy: in-place sed/perl edits were ruled out in this project because they risk corrupting the working tree with no undo. The issue therefore has to be fixed upstream rather than worked around.
  • Related note: the agent documentation advises splitting long oldStrings and re-reading between edits as a workaround for exactly this. That guidance exists because the tool fails, not because long anchors are wrong.
  • No stack trace or log output was produced; the failures surface only as tool error strings.

Activity

  1. github-actions commented on Sep 29, 2026

    @github-actions
    Contributor

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

    • #44996: Reports whitespace-normalized edit matching and misleading not-found behavior.
  2. maxx-ukoo commented on Oct 27, 2026

    @maxx-ukoo

    I have the same issue. Today I use glm-5 model with opencode 2.2.0.
    Logs:

    Let me create a simpler solution - use the SetText directive to preserve the code blocks:
    Edit wiki/src/pages/*********************************************
    Could not find oldString in wiki/src/pages/**********************************. It must match exactly, including whitespace and indentation.
    Let me take a different approach - ......
    
  3. ulab commented on Oct 28, 2026

    @ulab

    This is annoying, because the models fall for it again and again and always have to think and decide on a workaround. This takes time and tokens which add up.

    Could not find oldString in [file]. It must match exactly, including whitespace and indentation.
    ...
    I've identified a quirk of the tool: oldString fails with 4 spaces at the beginning, but 3 spaces or 0 spaces works. I'll work around this: line 17 remains unchanged (already the target text), and only lines 18–33 (3 spaces) will be replaced. First, revert ZZ:
    

    Apparently this happens because the edit tool uses fuzzy matching. I am new to this, but isn't an edit tool supposed to be precise?

  4. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for the detailed report!

    I checked the edit tool in v2.0.16. The "oldString and newString are identical" error comes from a plain oldString === newString check on the raw arguments. Nothing is trimmed or normalised first, so that error only appears when the two strings actually reached the tool identical. The lookup also tries an exact match first, so text that is really present byte-for-byte should be found. Both point to the arguments being changed before the tool ran, most likely in the model's output or the provider's tool-call handling, rather than in the matcher. To check this, could you share:

    1. The provider and model used in that session (e.g. anthropic/claude-..., openrouter/...).
    2. What the tool actually received for one failing call. The best source is the session itself, e.g. the tool call's input as shown in the TUI or a session export. What the agent said it sent isn't enough.
    3. A short description in your own words of what you did, what you expected and what you saw. The current text reads like an agent's summary of the session, so a few plain sentences help us confirm the details.

    You can reply here, or edit the issue. If you edit it, please also leave a comment saying you've updated it, so we know you're done.

    Related issues, most closely related first:

  5. opencodejr commented on Oct 31, 2026

    @opencodejr
    Contributor

    Closing this for now, since we haven't heard back. In v2.0.16 the edit tool compares the raw arguments exactly, so both errors suggest the arguments were changed before they reached the tool. To check that, we needed the provider and model, plus the tool-call input the tool actually received for one failing call.

    If it still happens, please reply with those details (a session export or the tool call's input as shown in the TUI works) and we can reopen. Thanks for the detailed write-up!

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions