{"record":{"id":"2c5f6e07e786d9aa","repo":"langchain-ai/deepagents","slug":"archive-rollback-failed-for-self-path-result-e","errorCode":null,"errorMessage":"archive rollback failed for {self.path}: {result.error}","messagePattern":"archive rollback failed for (.+?): (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"libs/code/deepagents_code/offload_middleware.py","lineNumber":621,"sourceCode":"    backend: BackendProtocol\n    path: str\n    existed: bool\n    previous: str\n\n    async def rollback(self) -> None:\n        \"\"\"Restore the exact archive snapshot from before the append.\n\n        Raises:\n            RuntimeError: If the backend cannot restore the snapshot.\n        \"\"\"\n        result = (\n            await self.backend.awrite(self.path, self.previous)\n            if self.existed\n            else await self.backend.adelete(self.path)\n        )\n        if result.error is not None:\n            msg = f\"archive rollback failed for {self.path}: {result.error}\"\n            raise RuntimeError(msg)\n\n\nclass _ForcedCompactionPlan(NamedTuple):\n    \"\"\"Checkpoint update plus its not-yet-written archive append.\"\"\"\n\n    summarization: SummarizationMiddleware\n    summary: str\n    state_cutoff: int\n    archive: _PendingArchive\n\n    def update(self, file_path: str | None) -> dict[str, Any]:\n        \"\"\"Build the summary update with the archive's settled path.\n\n        Returns:\n            State update containing the summary, cutoff, and archive path.\n        \"\"\"\n        return self.archive.update(file_path)\n","sourceCodeStart":603,"sourceCodeEnd":639,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/offload_middleware.py#L603-L639","documentation":"`_ArchiveAppend.rollback` restores the archive file to its previous content (rewriting the old bytes or deleting a newly created path). If the backend's `awrite`/`adelete` returns an error, the rollback itself failed and this RuntimeError is raised, meaning the archive may be left in a partially appended state that could not be undone.","triggerScenarios":"A checkpoint reservation fails after the archive append was written and the compensating `adelete`/`awrite` of the previous content returns an error (storage outage, permission change, eventual-consistency lag).","commonSituations":"Transient storage failures during offload cancellation; distributed backends where the just-written object is not yet visible for delete; quota exhaustion mid-offload.","solutions":["Inspect `result.error` and retry the rollback manually once the backend recovers.","Restore the archive manually from `self.previous` content (captured before the append).","Add resilience to the backend (retry policy, stronger consistency) to reduce rollback failures."],"exampleFix":"// before\nawait backend.adelete(self.path)\n// after (retry the compensating delete)\nfor _ in range(3):\n    result = await backend.adelete(self.path)\n    if result.error is None:\n        break","handlingStrategy":"try-catch","validationCode":"// cannot fully pre-validate; check backend writability beforehand\nprobe = await backend.awrite(probe_path, b\"\")\nassert probe.error is None, \"archive backend not writable; rollback would fail\"","typeGuard":"def rollback_capable(append: _ArchiveAppend) -> bool:\n    return append.previous is not None or not append.existed","tryCatchPattern":"try:\n    await offload(thread_id)\nexcept RuntimeError as e:\n    if \"archive rollback failed\" in str(e):\n        await manually_restore_archive(archive_path, captured_previous)\n    raise","preventionTips":["Capture archive content before appends so manual restoration is always possible.","Use a strongly consistent archive backend to avoid delete-after-write lag.","Monitor storage quota and permissions; rollbacks commonly fail for the same reason the write path degrades."],"tags":["archive","rollback","consistency","offload"],"backgroundTag":"rollback-failed","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}