{"record":{"id":"4fce72acbd724885","repo":"NousResearch/hermes-agent","slug":"failed-to-read-file-path","errorCode":null,"errorMessage":"Failed to read file: {path}","messagePattern":"Failed to read file: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"acp_adapter/edit_approval.py","lineNumber":109,"sourceCode":"        path=path,\n        old_text=_read_text_if_exists(path),\n        new_text=str(content),\n        arguments=dict(arguments),\n    )\n\n\ndef _proposal_for_patch_replace(arguments: dict[str, Any]) -> EditProposal:\n    path = str(arguments.get(\"path\") or \"\")\n    if not path:\n        raise ValueError(\"path required\")\n    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),","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/acp_adapter/edit_approval.py#L91-L127","documentation":"Raised by _proposal_for_patch_replace when _read_text_if_exists(path) returns None — meaning Path(path).expanduser() does not exist. A search/replace patch can only apply to an existing file (unlike write_file, which can create one), so the proposal builder refuses to continue when the target is absent. This fires before the fuzzy matcher, distinguishing 'file missing' from 'match not found'.","triggerScenarios":"A patch call targeting a file that was never created, was deleted, or whose path is wrong (typo, wrong relative root, ~ not expanded by the caller — note expanduser() here handles it, but a wrong cwd-relative path still misses).","commonSituations":"Agents patching files by remembered paths after the files were renamed; relative paths resolved from a different working directory than the agent assumed; first-edit attempts on files the agent intended to create with patch instead of write_file.","solutions":["Verify the file exists from the adapter's working directory; correct the path or create the file with write_file first.","Use absolute paths in patch calls to avoid cwd-relative mismatches.","If the file was deleted intentionally, recreate it with write_file before patching.","Catch this ValueError in the dispatcher and reply 'file not found' so the agent can self-correct."],"exampleFix":"# before\nold_text = _read_text_if_exists(path)\nif old_text is None:\n    raise ValueError(f\"Failed to read file: {path}\")\n\n# after — distinguish missing vs unreadable for the agent\nold_text = _read_text_if_exists(path)\nif old_text is None:\n    if not Path(path).expanduser().exists():\n        raise ValueError(f\"File does not exist: {path}\")\n    raise ValueError(f\"Failed to read file: {path}\")","handlingStrategy":"validation","validationCode":"from pathlib import Path\nif not Path(path).expanduser().exists():\n    return error_response(f\"File not found: {path} — create it with write_file first or fix the path\")","typeGuard":"def file_exists(path: str) -> bool:\n    return Path(path).expanduser().is_file()","tryCatchPattern":"try:\n    proposal = _proposal_for_patch_replace(arguments)\nexcept ValueError as err:\n    if \"Failed to read file\" in str(err):\n        # instruct the agent to re-check the path or use write_file to create\n        return {\"error\": {\"code\": -32602, \"message\": str(err)}}\n    raise","preventionTips":["Use absolute paths in patch calls to avoid cwd-relative misses","Create new files with write_file, never patch","Re-verify existence after long-running turns where files may have changed"],"tags":["acp","editor-integration","filesystem","patch","python"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}