{"record":{"id":"4308f8592994d0df","repo":"NousResearch/hermes-agent","slug":"cannot-read-abs-path-e","errorCode":null,"errorMessage":"cannot read {abs_path}: {e}","messagePattern":"cannot read (.+?): (.+?)","errorType":"exception","errorClass":"LSPProtocolError","httpStatus":null,"severity":"error","filePath":"agent/lsp/client.py","lineNumber":736,"sourceCode":"\n    # ------------------------------------------------------------------\n    # public file-sync API\n    # ------------------------------------------------------------------\n\n    async def open_file(self, path: str, *, language_id: str = \"plaintext\") -> int:\n        \"\"\"Send didOpen (first time) or didChange (subsequent) for ``path``.\n\n        Returns the new document version number that the agent's\n        ``wait_for_diagnostics`` should match against.\n        \"\"\"\n        if not self.is_running:\n            raise LSPProtocolError(\"client not running\")\n\n        abs_path = os.path.abspath(path)\n        try:\n            text = Path(abs_path).read_text(encoding=\"utf-8\", errors=\"replace\")\n        except OSError as e:\n            raise LSPProtocolError(f\"cannot read {abs_path}: {e}\") from e\n\n        uri = file_uri(abs_path)\n        doc = self._docs.get(abs_path)\n\n        if doc is not None and doc.version >= 0:\n            # Re-open: bump version, fire didChangeWatchedFiles + didChange.\n            await self._send_notification(\n                \"workspace/didChangeWatchedFiles\",\n                {\"changes\": [{\"uri\": uri, \"type\": 2}]},  # 2 = CHANGED\n            )\n            new_version = doc.version + 1\n            old_text = doc.text\n            content_changes: List[Dict[str, Any]]\n            if self._sync_kind == 2:\n                content_changes = [\n                    {\n                        \"range\": {\n                            \"start\": {\"line\": 0, \"character\": 0},","sourceCodeStart":718,"sourceCodeEnd":754,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/agent/lsp/client.py#L718-L754","documentation":"LSPProtocolError raised by open_file when reading the local file to send in didOpen/didChange fails with an OSError. The client must send the document text to the server, so an unreadable or missing path aborts the sync. Note errors='replace' is already set, so encoding problems do NOT trigger this — only real I/O failures.","triggerScenarios":"open_file on a path that was deleted between listing and sync; a directory passed instead of a file; permission denied (mode 000, foreign ownership); path too long or otherwise invalid for the OS.","commonSituations":"Editor/agent racing file deletion or rename (git checkout switching branches); paths from external systems that no longer exist; sandboxed environments without read access to the workspace.","solutions":["Validate the file exists and is readable before syncing (Path.is_file() plus an os.access check).","If the file was renamed/deleted intentionally, close it on the server side (didClose) instead of opening it.","Fix permissions or run the agent with read access to the workspace root."],"exampleFix":"# before\nawait client.open_file(deleted_path)  # LSPProtocolError: cannot read\n\n# after\nfrom pathlib import Path\np = Path(path)\nif not p.is_file():\n    await client.close_file(path)  # sync deletion with the server\nelse:\n    await client.open_file(path)","handlingStrategy":"validation","validationCode":"import os\nfrom pathlib import Path\n\ndef file_readable(path: str) -> bool:\n    p = Path(path)\n    return p.is_file() and os.access(p, os.R_OK)","typeGuard":null,"tryCatchPattern":"try:\n    version = await client.open_file(path)\nexcept LSPProtocolError as e:\n    if \"cannot read\" in str(e):\n        skip_or_close_document(path)  # deleted/unreadable: sync deletion instead\n    else:\n        raise","preventionTips":["Check Path.is_file() before syncing; editors racing deletions are the usual cause.","Sync deletions with didClose instead of trying to open vanished files.","Run the agent with read access to the whole workspace root."],"tags":["lsp","filesystem","validation"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}