langchain-ai/deepagents · error · RuntimeError
archive read failed; refusing to overwrite existing history
Error message
archive read failed; refusing to overwrite existing history
What it means
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.
Source
Thrown at libs/code/deepagents_code/offload_middleware.py:895
Returns:
The unchanged backend download responses.
"""
if any(
response.error is not None and response.error != FILE_NOT_FOUND
for response in responses
):
self._read_failed = True
return responses
def _ensure_read_succeeded(self) -> None:
"""Raise when a prior archive read failed in this operation.
Raises:
RuntimeError: If the prerequisite archive read failed.
"""
if self._read_failed:
msg = "archive read failed; refusing to overwrite existing history"
raise RuntimeError(msg)
def download_files(self, paths: list[str]) -> list[FileDownloadResponse]:
"""Delegate a synchronous read while recording failures.
Args:
paths: Backend paths to read.
Returns:
The backend download responses.
"""
try:
responses = self._backend.download_files(paths)
except Exception:
self._read_failed = True
raise
return self._record_response_errors(responses)
async def adownload_files(self, paths: list[str]) -> list[FileDownloadResponse]:View on GitHub (pinned to a1af029e6e)
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.
Example fix
// before: blind write after failed read
await backend.awrite(path, content)
// after: confirm read path first
resp = await backend.adownload_files([path])
if resp and resp[0].error is None:
await backend.awrite(path, content) Defensive patterns
Strategy: try-catch
Validate before calling
resp = (await backend.adownload_files([path]) or [None])[0]
if resp is not None and resp.error is not None:
raise ArchiveUnreadable(f"cannot safely mutate {path}: {resp.error}") Type guard
def can_mutate(backend: RecordingBackend, path: str) -> bool:
return not backend._read_failed # or track via a public property Try / catch
try:
await backend.awrite(path, content)
except RuntimeError as e:
if "refusing to overwrite existing history" in str(e):
await repair_and_reconnect(backend)
# re-issue the mutation only after a successful read
raise Prevention
- 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.
When it happens
Trigger: Calling `write`, `awrite`, `edit`, or `aedit` through the recording backend after its `download_files`/`adownload_files` returned an error for the target path.
Common situations: 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.
Related errors
- archive backend returned no response for {path}
- archive read failed for {path}: {response.error}
- archive rollback failed for {self.path}: {result.error}
- Offload server returned an invalid cancellation acknowledgem
- Offload server completed without a typed result.
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/6935fb083958a30e.
Report an issue: GitHub.