{"record":{"id":"256cd9d5ddbee391","repo":"langchain-ai/deepagents","slug":"offload-did-not-complete-after-offload-max-resum","errorCode":null,"errorMessage":"Offload did not complete after {_OFFLOAD_MAX_RESUME_ROUNDS} hook rounds. Check the server log for the hook invocations it requested.","messagePattern":"Offload did not complete after (.+?) hook rounds\\. Check the server log for the hook invocations it requested\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/client/remote_client.py","lineNumber":479,"sourceCode":"                graph=graph,\n                thread_id=thread_id,\n                operation_id=operation_id,\n            )\n        # The server only re-requests an invocation id it has not been given, so\n        # exhaustion means this many *distinct* ids. That is either genuinely\n        # many hooks or an unstable invocation-id derivation server-side; log the\n        # ids so the two are distinguishable, and do not assert a cause in the\n        # user-facing message.\n        logger.warning(\n            \"Offload exceeded %d hook rounds; fulfilled invocation ids: %s\",\n            _OFFLOAD_MAX_RESUME_ROUNDS,\n            sorted(hook_responses),\n        )\n        msg = (\n            f\"Offload did not complete after {_OFFLOAD_MAX_RESUME_ROUNDS} hook \"\n            \"rounds. Check the server log for the hook invocations it requested.\"\n        )\n        raise RuntimeError(msg)\n\n    async def astream(\n        self,\n        input: dict | Any,  # noqa: A002, ANN401\n        *,\n        stream_mode: list[str] | None = None,\n        subgraphs: bool = False,\n        config: Mapping[str, Any] | None = None,\n        context: Any | None = None,  # noqa: ANN401\n        durability: str | None = None,  # noqa: ARG002\n    ) -> AsyncIterator[tuple[tuple[str, ...], str, Any]]:\n        \"\"\"Stream agent execution, yielding tuples matching Pregel's format.\n\n        Delegates to `RemoteGraph.astream` (which handles `messages-tuple`\n        negotiation, SSE routing, and namespace parsing) and converts the raw\n        message dicts into LangChain message objects for the adapter.\n\n        Args:","sourceCodeStart":461,"sourceCodeEnd":497,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/client/remote_client.py#L461-L497","documentation":"`aoffload` loops at most `_OFFLOAD_MAX_RESUME_ROUNDS` hook fulfillment rounds; the final iteration only POSTs the last fulfillment and reads the result. If after that many rounds the server still responds with hook interrupts instead of a `complete` result, the client logs the fulfilled invocation ids at WARNING and raises this RuntimeError. Exhaustion means either genuinely that many distinct hooks, or an unstable invocation-id derivation server-side causing the same id to be re-requested.","triggerScenarios":"Server requests more than `_OFFLOAD_MAX_RESUME_ROUNDS` distinct hook invocations during one offload, or re-requests ids because client fulfillments were never correlated server-side (e.g. unstable/changed invocation ids per round).","commonSituations":"A runaway server hook loop (a hook whose fulfillment triggers another hook endlessly); server-side derivation of `invocation_id` that changes between rounds so prior answers never match; a stuck server that never reaches `status: complete`.","solutions":["Check the server log — the client logged the sorted fulfilled invocation ids at WARNING; compare them to what the server requested to distinguish 'many hooks' from 'unstable ids'.","If the same logical hook is re-requested with new ids each round, fix the server-side invocation-id derivation to be deterministic per operation.","Reduce the number of hooks the offloaded operation can trigger, or split the work into smaller offloads.","Upgrade server/client to a matched version, then retry the operation."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for attempt in range(2):\n    try:\n        result = await agent.aoffload(config=config, context=ctx, fulfill_hook=hook)\n        break\n    except RuntimeError as exc:\n        if \"did not complete after\" in str(exc) and attempt == 0:\n            logging.warning(\"Offload hit hook-round limit; inspecting server logs before retry\")\n            continue\n        raise","preventionTips":["Read the WARNING log listing fulfilled invocation ids to detect unstable server-side id derivation.","Bound the number of hooks an offloaded operation can trigger.","Keep invocation-id derivation deterministic per operation on the server."],"tags":["offload","hooks","retry-limit","protocol"],"backgroundTag":"hook-round-limit-exceeded","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}