{"record":{"id":"6935fb083958a30e","repo":"langchain-ai/deepagents","slug":"archive-read-failed-refusing-to-overwrite-existin","errorCode":null,"errorMessage":"archive read failed; refusing to overwrite existing history","messagePattern":"archive read failed; refusing to overwrite existing history","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/offload_middleware.py","lineNumber":895,"sourceCode":"        Returns:\n            The unchanged backend download responses.\n        \"\"\"\n        if any(\n            response.error is not None and response.error != FILE_NOT_FOUND\n            for response in responses\n        ):\n            self._read_failed = True\n        return responses\n\n    def _ensure_read_succeeded(self) -> None:\n        \"\"\"Raise when a prior archive read failed in this operation.\n\n        Raises:\n            RuntimeError: If the prerequisite archive read failed.\n        \"\"\"\n        if self._read_failed:\n            msg = \"archive read failed; refusing to overwrite existing history\"\n            raise RuntimeError(msg)\n\n    def download_files(self, paths: list[str]) -> list[FileDownloadResponse]:\n        \"\"\"Delegate a synchronous read while recording failures.\n\n        Args:\n            paths: Backend paths to read.\n\n        Returns:\n            The backend download responses.\n        \"\"\"\n        try:\n            responses = self._backend.download_files(paths)\n        except Exception:\n            self._read_failed = True\n            raise\n        return self._record_response_errors(responses)\n\n    async def adownload_files(self, paths: list[str]) -> list[FileDownloadResponse]:","sourceCodeStart":877,"sourceCodeEnd":913,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/offload_middleware.py#L877-L913","documentation":"A file-backend wrapper records whether the prerequisite archive read failed; `_ensure_read_succeeded` is checked before any mutating operation (write/edit and their async variants). If the earlier read failed, mutating is refused with this RuntimeError to guarantee the wrapper never overwrites existing conversation history with content based on a stale or missing snapshot.","triggerScenarios":"Calling `write`, `awrite`, `edit`, or `aedit` through the recording backend after its `download_files`/`adownload_files` returned an error for the target path.","commonSituations":"Transient archive-backend failure followed by an automatic save/edit attempt in the same session; tests driving mutations without seeding readable archive state; backend connectivity dropped mid-session.","solutions":["Resolve the underlying read failure (connectivity, permissions), then retry the operation through a healthy backend.","Verify the archive path exists and is readable before issuing writes.","If running in a test, seed the fake backend with a successful download response before mutating."],"exampleFix":"// before: blind write after failed read\nawait backend.awrite(path, content)\n// after: confirm read path first\nresp = await backend.adownload_files([path])\nif resp and resp[0].error is None:\n    await backend.awrite(path, content)","handlingStrategy":"try-catch","validationCode":"resp = (await backend.adownload_files([path]) or [None])[0]\nif resp is not None and resp.error is not None:\n    raise ArchiveUnreadable(f\"cannot safely mutate {path}: {resp.error}\")","typeGuard":"def can_mutate(backend: RecordingBackend, path: str) -> bool:\n    return not backend._read_failed  # or track via a public property","tryCatchPattern":"try:\n    await backend.awrite(path, content)\nexcept RuntimeError as e:\n    if \"refusing to overwrite existing history\" in str(e):\n        await repair_and_reconnect(backend)\n        # re-issue the mutation only after a successful read\n    raise","preventionTips":["Verify archive reads succeed before starting a session that will save or edit.","Do not swallow download errors earlier in the pipeline — they poison later mutations.","In tests, seed the fake backend with successful responses for every path you mutate."],"tags":["archive","read-failure","safety","offload"],"backgroundTag":"stale-read-protection","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}