langchain-ai/deepagents · critical · RuntimeError

archive rollback failed for {self.path}: {result.error}

Error message

archive rollback failed for {self.path}: {result.error}

What it means

`_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.

Source

Thrown at libs/code/deepagents_code/offload_middleware.py:621

    backend: BackendProtocol
    path: str
    existed: bool
    previous: str

    async def rollback(self) -> None:
        """Restore the exact archive snapshot from before the append.

        Raises:
            RuntimeError: If the backend cannot restore the snapshot.
        """
        result = (
            await self.backend.awrite(self.path, self.previous)
            if self.existed
            else await self.backend.adelete(self.path)
        )
        if result.error is not None:
            msg = f"archive rollback failed for {self.path}: {result.error}"
            raise RuntimeError(msg)


class _ForcedCompactionPlan(NamedTuple):
    """Checkpoint update plus its not-yet-written archive append."""

    summarization: SummarizationMiddleware
    summary: str
    state_cutoff: int
    archive: _PendingArchive

    def update(self, file_path: str | None) -> dict[str, Any]:
        """Build the summary update with the archive's settled path.

        Returns:
            State update containing the summary, cutoff, and archive path.
        """
        return self.archive.update(file_path)

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Inspect `result.error` and retry the rollback manually once the backend recovers.
  2. Restore the archive manually from `self.previous` content (captured before the append).
  3. Add resilience to the backend (retry policy, stronger consistency) to reduce rollback failures.

Example fix

// before
await backend.adelete(self.path)
// after (retry the compensating delete)
for _ in range(3):
    result = await backend.adelete(self.path)
    if result.error is None:
        break
Defensive patterns

Strategy: try-catch

Validate before calling

// cannot fully pre-validate; check backend writability beforehand
probe = await backend.awrite(probe_path, b"")
assert probe.error is None, "archive backend not writable; rollback would fail"

Type guard

def rollback_capable(append: _ArchiveAppend) -> bool:
    return append.previous is not None or not append.existed

Try / catch

try:
    await offload(thread_id)
except RuntimeError as e:
    if "archive rollback failed" in str(e):
        await manually_restore_archive(archive_path, captured_previous)
    raise

Prevention

When it happens

Trigger: 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).

Common situations: Transient storage failures during offload cancellation; distributed backends where the just-written object is not yet visible for delete; quota exhaustion mid-offload.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/2c5f6e07e786d9aa. Report an issue: GitHub.