Aider-AI/aider · error · ValueError
# {len(failed)} SEARCH/REPLACE {blocks} failed to match!\n
Error message
# {len(failed)} SEARCH/REPLACE {blocks} failed to match!\n What it means
Raised by EditBlockCoder after processing SEARCH/REPLACE blocks when at least one block failed to apply. The value is a long, LLM-facing report: for each failed block it shows the SEARCH/REPLACE pair, a 'did you mean' suggestion of similar actual lines from the file, and notes when the REPLACE text is already present. In aider's normal flow this ValueError is caught and fed back to the model so it can retry with corrected blocks.
Source
Thrown at aider/coders/editblock_coder.py:124
"""
if updated in content and updated:
res += f"""Are you sure you need this SEARCH/REPLACE block?
The REPLACE lines are already in {path}!
"""
res += (
"The SEARCH section must exactly match an existing block of lines including all white"
" space, comments, indentation, docstrings, etc\n"
)
if passed:
pblocks = "block" if len(passed) == 1 else "blocks"
res += f"""
# The other {len(passed)} SEARCH/REPLACE {pblocks} were applied successfully.
Don't re-send them.
Just reply with fixed versions of the {blocks} above that failed to match.
"""
raise ValueError(res)
def prep(content):
if content and not content.endswith("\n"):
content += "\n"
lines = content.splitlines(keepends=True)
return content, lines
def perfect_or_whitespace(whole_lines, part_lines, replace_lines):
# Try for a perfect match
res = perfect_replace(whole_lines, part_lines, replace_lines)
if res:
return res
# Try being flexible about leading whitespace
res = replace_part_with_missing_leading_whitespace(whole_lines, part_lines, replace_lines)
if res:View on GitHub (pinned to 5dc9490bb3)
Solutions
- Let the loop retry: in aider this error text is designed to be sent back to the LLM so it re-emits corrected blocks — don't abort on the first occurrence.
- Re-read the target file and re-send it to the model (e.g. /drop + /add, or reset chat) so SEARCH matches current on-disk content.
- Check whitespace: run the file through a viewer that shows tabs/trailing spaces and line endings (git diff --check, file/dos2unix for CRLF).
- Use a more tolerant edit format (--edit-format udiff or patch) if the model repeatedly fails exact matching.
- If calling apply_edits programmatically, validate each SEARCH block against file content yourself before applying the batch.
Example fix
# before
edits = parse_edits(llm_reply)
coder.apply_edits(edits) # raises ValueError listing failed blocks
# after
edits = parse_edits(llm_reply)
content = io.read_text(path)
safe = [e for e in edits if e[1] in content] # only blocks whose SEARCH exists verbatim
if len(safe) < len(edits):
llm_reply = resend_errors_to_model(edits, safe) # feed failures back for retry
coder.apply_edits(safe) Defensive patterns
Strategy: retry
Validate before calling
def split_edits_by_match(edits, content: str):
ok, failed = [], []
for e in edits:
(ok if e[1] in content else failed).append(e)
return ok, failed # apply ok; send failed back to the model for correction Try / catch
try:
coder.apply_edits(edits)
except ValueError as e:
msg = str(e)
if "SEARCH/REPLACE" in msg and "failed to match" in msg:
# designed to be fed back to the LLM — retry the turn
reply = model.retry_with_feedback(msg)
coder.apply_edits(parse_edits(reply))
else:
raise Prevention
- Keep the model's view of files fresh: re-add files after external edits instead of relying on stale chat history.
- Prefer diff/udiff/patch formats with fuzz tolerance when a model persistently fails exact SEARCH matching.
- Verify SEARCH blocks exist verbatim in file content before applying a batch of edits programmatically.
- Normalize line endings (CRLF vs LF) in edited files to avoid byte-level match failures.
When it happens
Trigger: The model emits a <<<<<<< SEARCH section whose lines do not byte-for-byte match the current file: wrong indentation, changed whitespace, stale copy of a file edited earlier in the session, or a SEARCH block for lines that were already replaced. raised in _finalize_and_raise after failed is non-empty.
Common situations: File drifted from what the model saw (concurrent edits, earlier blocks in the same reply already applied); model hallucinating slightly different whitespace/comments; tabs vs spaces; trailing whitespace or line-ending (CRLF) mismatches; the REPLACE content already applied so the SEARCH context no longer exists.
Related errors
- Bad/missing filename. The filename must be alone on the line
- Expected `=======`
- Expected `>>>>>>> REPLACE` or `=======`
- {processed}\n^^^ {err}
- Delete File action missing path.
AI-assisted analysis of Aider-AI/aider@5dc9490bb3 (2026-08-15).
Data as JSON: /api/errors/34a1ec9eeb3f7834.
Report an issue: GitHub.