{"record":{"id":"7a75892684396d3e","repo":"langchain-ai/deepagents","slug":"archive-backend-returned-no-response-for-path","errorCode":null,"errorMessage":"archive backend returned no response for {path}","messagePattern":"archive backend returned no response for (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/offload_middleware.py","lineNumber":571,"sourceCode":"            self.summary,\n            file_path,\n            self.state_cutoff,\n            self.session_id,\n        )\n\n    async def _previous_content(self, path: str) -> tuple[bool, str]:\n        \"\"\"Read the archive snapshot needed to undo an uncommitted append.\n\n        Returns:\n            Whether the archive existed and its prior UTF-8 content.\n\n        Raises:\n            RuntimeError: If the backend cannot return the archive snapshot.\n        \"\"\"\n        responses = await self.backend.adownload_files([path])\n        if not responses:\n            msg = f\"archive backend returned no response for {path}\"\n            raise RuntimeError(msg)\n        response = responses[0]\n        if response.error == FILE_NOT_FOUND:\n            return False, \"\"\n        if response.error is not None:\n            msg = f\"archive read failed for {path}: {response.error}\"\n            raise RuntimeError(msg)\n        content = response.content or b\"\"\n        return True, content.decode(\"utf-8\")\n\n    async def write(self) -> _ArchiveAppend | None:\n        \"\"\"Append staged messages and retain enough state for rollback.\n\n        Returns:\n            The reversible append, or `None` when the SDK could not write it.\n        \"\"\"\n        path = self.summarization._get_history_path(self.session_id)\n        existed, previous = await self._previous_content(path)\n        guard = cast(\"BackendProtocol\", _ArchiveReadGuard(self.backend))","sourceCodeStart":553,"sourceCodeEnd":589,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/offload_middleware.py#L553-L589","documentation":"`_previous_content` reads the archived conversation snapshot from the archive backend via `adownload_files([path])` before appending. If the backend returns an empty response list, the code cannot distinguish 'missing' (empty list vs FILE_NOT_FOUND) and raises RuntimeError rather than silently treating history as absent, which would risk overwriting existing archives.","triggerScenarios":"A misbehaving or stubbed backend whose `adownload_files` returns `[]` for the archive path; a custom CompositeBackend child that swallows responses; a storage layer returning no rows without an error code.","commonSituations":"Custom archive backends (S3/DB-backed) that return empty lists on transient store errors; test fakes that forget to enqueue a response; backend wrappers that filter out failed downloads instead of reporting them as error responses.","solutions":["Fix the backend so it returns a FileDownloadResponse with `error` set instead of returning an empty list.","Check backend connectivity/permissions so `adownload_files` can actually fetch the archive path.","If a wrapper intentionally drops responses, make it surface FILE_NOT_FOUND for missing keys."],"exampleFix":"// before (custom backend)\nasync def adownload_files(self, paths):\n    return [r for r in self._fetch(paths) if r is not None]\n// after\nasync def adownload_files(self, paths):\n    return self._fetch(paths)  # return one response per path, with error set on failure","handlingStrategy":"type-guard","validationCode":"responses = await backend.adownload_files([path])\nif not responses:\n    raise BackendMisconfigured(f\"{type(backend).__name__} returned no responses for {path}\")","typeGuard":"def has_download_response(responses: list[FileDownloadResponse] | None) -> bool:\n    return bool(responses) and len(responses) > 0","tryCatchPattern":"try:\n    await offload(thread_id)\nexcept RuntimeError as e:\n    if \"returned no response\" in str(e):\n        check_backend_health(backend)  # fix the custom/stub backend\n    raise","preventionTips":["Contract-test custom backends: one response per requested path, errors set on the response, never an empty list.","Avoid wrapper backends that silently drop failed downloads.","Run offload smoke tests against your storage backend before production."],"tags":["archive","backend","offload","empty-response"],"backgroundTag":"empty-backend-response","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}