{"record":{"id":"34a1ec9eeb3f7834","repo":"Aider-AI/aider","slug":"len-failed-search-replace-blocks-failed-to","errorCode":null,"errorMessage":"# {len(failed)} SEARCH/REPLACE {blocks} failed to match!\\n","messagePattern":"# (.+?) SEARCH/REPLACE (.+?) failed to match!\\\\n","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aider/coders/editblock_coder.py","lineNumber":124,"sourceCode":"\"\"\"\n\n            if updated in content and updated:\n                res += f\"\"\"Are you sure you need this SEARCH/REPLACE block?\nThe REPLACE lines are already in {path}!\n\n\"\"\"\n        res += (\n            \"The SEARCH section must exactly match an existing block of lines including all white\"\n            \" space, comments, indentation, docstrings, etc\\n\"\n        )\n        if passed:\n            pblocks = \"block\" if len(passed) == 1 else \"blocks\"\n            res += f\"\"\"\n# The other {len(passed)} SEARCH/REPLACE {pblocks} were applied successfully.\nDon't re-send them.\nJust reply with fixed versions of the {blocks} above that failed to match.\n\"\"\"\n        raise ValueError(res)\n\n\ndef prep(content):\n    if content and not content.endswith(\"\\n\"):\n        content += \"\\n\"\n    lines = content.splitlines(keepends=True)\n    return content, lines\n\n\ndef perfect_or_whitespace(whole_lines, part_lines, replace_lines):\n    # Try for a perfect match\n    res = perfect_replace(whole_lines, part_lines, replace_lines)\n    if res:\n        return res\n\n    # Try being flexible about leading whitespace\n    res = replace_part_with_missing_leading_whitespace(whole_lines, part_lines, replace_lines)\n    if res:","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/Aider-AI/aider/blob/5dc9490bb35f9729ef2c95d00a19ccd30c26339c/aider/coders/editblock_coder.py#L106-L142","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nedits = parse_edits(llm_reply)\ncoder.apply_edits(edits)  # raises ValueError listing failed blocks\n\n# after\nedits = parse_edits(llm_reply)\ncontent = io.read_text(path)\nsafe = [e for e in edits if e[1] in content]  # only blocks whose SEARCH exists verbatim\nif len(safe) < len(edits):\n    llm_reply = resend_errors_to_model(edits, safe)  # feed failures back for retry\ncoder.apply_edits(safe)","handlingStrategy":"retry","validationCode":"def split_edits_by_match(edits, content: str):\n    ok, failed = [], []\n    for e in edits:\n        (ok if e[1] in content else failed).append(e)\n    return ok, failed  # apply ok; send failed back to the model for correction","typeGuard":null,"tryCatchPattern":"try:\n    coder.apply_edits(edits)\nexcept ValueError as e:\n    msg = str(e)\n    if \"SEARCH/REPLACE\" in msg and \"failed to match\" in msg:\n        # designed to be fed back to the LLM — retry the turn\n        reply = model.retry_with_feedback(msg)\n        coder.apply_edits(parse_edits(reply))\n    else:\n        raise","preventionTips":["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."],"tags":["aider","search-replace","edit-matching","llm-output"],"backgroundTag":null,"analyzedSha":"5dc9490bb35f9729ef2c95d00a19ccd30c26339c","analyzedAt":"2026-08-15T05:40:10.498Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}