{"record":{"id":"67913437bed02db7","repo":"NousResearch/hermes-agent","slug":"error-or-could-not-find-match-for-old-string-in","errorCode":null,"errorMessage":"{error or 'Could not find match for old_string in {path}'}","messagePattern":"\\{error or 'Could not find match for old_string in \\{path\\}'\\}","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"acp_adapter/edit_approval.py","lineNumber":120,"sourceCode":"    old_string = arguments.get(\"old_string\")\n    new_string = arguments.get(\"new_string\")\n    if old_string is None or new_string is None:\n        raise ValueError(\"old_string and new_string required\")\n\n    old_text = _read_text_if_exists(path)\n    if old_text is None:\n        raise ValueError(f\"Failed to read file: {path}\")\n\n    from tools.fuzzy_match import fuzzy_find_and_replace\n\n    new_text, match_count, _strategy, error = fuzzy_find_and_replace(\n        old_text,\n        str(old_string),\n        str(new_string),\n        bool(arguments.get(\"replace_all\", False)),\n    )\n    if error or match_count == 0:\n        raise ValueError(error or f\"Could not find match for old_string in {path}\")\n\n    return EditProposal(\n        tool_name=\"patch\",\n        path=path,\n        old_text=old_text,\n        new_text=new_text,\n        arguments=dict(arguments),\n    )\n\n\ndef _extract_v4a_patch_paths(patch_body: str) -> list[str]:\n    paths: list[str] = []\n    for match in re.finditer(\n        r'^\\*\\*\\*\\s+(?:Update|Add|Delete)\\s+File:\\s*(.+)$',\n        patch_body,\n        re.MULTILINE,\n    ):\n        path = match.group(1).strip()","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/acp_adapter/edit_approval.py#L102-L138","documentation":"Raised by _proposal_for_patch_replace after running tools.fuzzy_match.fuzzy_find_and_replace on the file's current content: the matcher reported an error, or found zero occurrences of old_string. Hermes' patch pipeline uses fuzzy matching to tolerate whitespace drift, so reaching this error means even fuzzy matching could not anchor old_string in the file — typically because the file content diverged from what the caller expected (already edited, different version, old_string from an older read).","triggerScenarios":"A patch whose old_string does not appear in the current file: the file was modified since the agent last read it, old_string was hand-typed with different indentation/quotes, replace_all=False with an old_string that matches nothing, or the fuzzy matcher returned a strategy error (e.g. ambiguous multi-match where one was required).","commonSituations":"Concurrent edits (two agents or agent+human editing the same file), stale context after context compression, copying old_string from a different branch, tab-vs-space drift beyond fuzzy tolerance.","solutions":["Re-read the file and rebuild old_string from its current exact content, then retry the patch.","If the edit was already applied by another writer, verify the desired end state before re-patching.","Reduce old_string to a smaller unique anchor line to make matching robust.","For replace_all scenarios, confirm the target string actually occurs (search first)."],"exampleFix":"# before\nif error or match_count == 0:\n    raise ValueError(error or f\"Could not find match for old_string in {path}\")\n\n# after — report near-misses so the caller can self-correct\nif error or match_count == 0:\n    best = fuzzy_best_ratio(old_text, str(old_string))\n    hint = f\" (closest similarity {best:.2f})\" if best else \"\"\n    raise ValueError(error or f\"Could not find match for old_string in {path}{hint}; re-read the file and retry\")","handlingStrategy":"try-catch","validationCode":"from pathlib import Path\ncurrent = Path(path).expanduser().read_text(encoding='utf-8', errors='replace')\nif old_string not in current:\n    # exact anchor absent — re-read and rebuild old_string before patching\n    raise SystemExit('stale old_string; refresh context')","typeGuard":"def old_string_present(text: str, old_string: str) -> bool:\n    return old_string in text","tryCatchPattern":"try:\n    proposal = _proposal_for_patch_replace(arguments)\nexcept ValueError as err:\n    if 'Could not find match' in str(err):\n        fresh = Path(path).expanduser().read_text(encoding='utf-8', errors='replace')\n        # rebuild old_string from `fresh` and retry once; surface to agent on second failure\n    else:\n        raise","preventionTips":["Always re-read the file immediately before constructing old_string","Prefer short unique anchor lines over long multi-line snippets","Fail fast on stale context instead of patching from memory","Use replace_all only after confirming the string occurs"],"tags":["acp","editor-integration","patch","fuzzy-match","stale-context","python"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}