langchain-ai/deepagents · error · RuntimeError

Offload did not complete after {_OFFLOAD_MAX_RESUME_ROUNDS}

Error message

Offload did not complete after {_OFFLOAD_MAX_RESUME_ROUNDS} hook rounds. Check the server log for the hook invocations it requested.

What it means

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

Source

Thrown at libs/code/deepagents_code/client/remote_client.py:479

                graph=graph,
                thread_id=thread_id,
                operation_id=operation_id,
            )
        # The server only re-requests an invocation id it has not been given, so
        # exhaustion means this many *distinct* ids. That is either genuinely
        # many hooks or an unstable invocation-id derivation server-side; log the
        # ids so the two are distinguishable, and do not assert a cause in the
        # user-facing message.
        logger.warning(
            "Offload exceeded %d hook rounds; fulfilled invocation ids: %s",
            _OFFLOAD_MAX_RESUME_ROUNDS,
            sorted(hook_responses),
        )
        msg = (
            f"Offload did not complete after {_OFFLOAD_MAX_RESUME_ROUNDS} hook "
            "rounds. Check the server log for the hook invocations it requested."
        )
        raise RuntimeError(msg)

    async def astream(
        self,
        input: dict | Any,  # noqa: A002, ANN401
        *,
        stream_mode: list[str] | None = None,
        subgraphs: bool = False,
        config: Mapping[str, Any] | None = None,
        context: Any | None = None,  # noqa: ANN401
        durability: str | None = None,  # noqa: ARG002
    ) -> AsyncIterator[tuple[tuple[str, ...], str, Any]]:
        """Stream agent execution, yielding tuples matching Pregel's format.

        Delegates to `RemoteGraph.astream` (which handles `messages-tuple`
        negotiation, SSE routing, and namespace parsing) and converts the raw
        message dicts into LangChain message objects for the adapter.

        Args:

View on GitHub (pinned to a1af029e6e)

Solutions

  1. 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'.
  2. 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.
  3. Reduce the number of hooks the offloaded operation can trigger, or split the work into smaller offloads.
  4. Upgrade server/client to a matched version, then retry the operation.
Defensive patterns

Strategy: retry

Try / catch

for attempt in range(2):
    try:
        result = await agent.aoffload(config=config, context=ctx, fulfill_hook=hook)
        break
    except RuntimeError as exc:
        if "did not complete after" in str(exc) and attempt == 0:
            logging.warning("Offload hit hook-round limit; inspecting server logs before retry")
            continue
        raise

Prevention

When it happens

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

Common situations: 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`.

Related errors


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