langchain-ai/deepagents · error · RuntimeError

Offload hook request has no invocation id.

Error message

Offload hook request has no invocation id.

What it means

Inside an `interrupt` response, the hook request's inner `request` object must carry a non-empty string `invocation_id` — the key the client uses to key its fulfillment into `hook_responses` for the next round-trip. When it is absent, empty, or not a string, the client raises this RuntimeError because fulfillment could not be correlated.

Source

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

            if not isinstance(response, dict):
                msg = "Offload server returned a non-object response."
                raise TypeError(msg)
            status = response.get("status")
            if status == "complete":
                return _validated_offload_result(response.get("result"))
            request = response.get("request")
            if status != "interrupt" or not is_hook_interrupt_payload(request):
                msg = "Offload server returned an invalid operation response."
                raise RuntimeError(msg)
            invocation = request.get("request")
            invocation_id = (
                invocation.get("invocation_id")
                if isinstance(invocation, dict)
                else None
            )
            if not isinstance(invocation_id, str) or not invocation_id:
                msg = "Offload hook request has no invocation id."
                raise RuntimeError(msg)
            logger.debug(
                "Offload round %d fulfilling hook invocation %s",
                round_index,
                invocation_id,
            )
            if round_index == _OFFLOAD_MAX_RESUME_ROUNDS:
                # The extra iteration exists to POST the last fulfillment and
                # read the result, not to answer one more hook. Without this the
                # loop fulfills 33 hooks and then reports "after 32 rounds".
                break
            hook_responses[invocation_id] = await _await_offload_step(
                fulfill_hook(request),
                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

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Upgrade or fix the server so every hook interrupt includes a non-empty string `invocation_id`.
  2. Log the failing interrupt payload (`request`) to confirm the field name and type the server actually emits.
  3. If a rename occurred, align the server's field name with the client's expected `invocation_id` (or vice versa in a matched release pair).
  4. Retry the operation once — a transient partial payload from a crashing server may resolve on a fresh offload.
Defensive patterns

Strategy: type-guard

Type guard

def has_invocation_id(hook_request: object) -> bool:
    inner = hook_request.get("request") if isinstance(hook_request, dict) else None
    return isinstance(inner, dict) and isinstance(inner.get("invocation_id"), str) and bool(inner["invocation_id"])

Try / catch

try:
    result = await agent.aoffload(config=config, context=ctx, fulfill_hook=hook)
except RuntimeError as exc:
    if "no invocation id" in str(exc):
        logging.error("Server sent a hook interrupt without invocation_id; fix server hook executor")
    else:
        raise

Prevention

When it happens

Trigger: Server sends an interrupt whose `request.request` is not a dict, is missing `invocation_id`, or has `invocation_id` set to null/empty/non-string.

Common situations: A custom server's hook executor that forgets to assign invocation ids; server/client schema drift where the id field was renamed (e.g. `id` vs `invocation_id`); partially-constructed interrupt payloads after a server error.

Related errors


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