langchain-ai/deepagents · error · RuntimeError

Received hook invocation interrupt without a HooksRuntime

Error message

Received hook invocation interrupt without a HooksRuntime

What it means

HookManager.fulfill_interrupt resolves a Hooks v2 invocation interrupt by delegating to a HooksRuntime via fulfill_hook_interrupt. If the manager was constructed without a runtime (self._runtime is None), there is no engine able to execute the hook callback, so it raises RuntimeError rather than silently failing.

Source

Thrown at libs/code/deepagents_code/hooks/manager.py:537

    async def fulfill_interrupt(self, payload: object) -> dict[str, object]:
        """Execute one server-owned hook interrupt on the client runtime.

        Args:
            payload: Raw LangGraph interrupt value.

        Returns:
            Resume value for `Command(resume=...)`.

        Raises:
            RuntimeError: If hooks are unavailable, or the payload is not a
                parseable hook invocation.
        """
        from deepagents_code.hooks.client import fulfill_hook_interrupt

        runtime = self._runtime
        if runtime is None:
            msg = "Received hook invocation interrupt without a HooksRuntime"
            raise RuntimeError(msg)
        resume = await fulfill_hook_interrupt(runtime, payload)
        if resume is None:
            msg = "Failed to parse hook interrupt"
            raise RuntimeError(msg)
        return resume

    async def fulfill_pending_interrupts(
        self,
        pending: Mapping[str, object],
    ) -> dict[str, dict[str, object]]:
        """Execute a batch of server-owned hook interrupts.

        Args:
            pending: LangGraph interrupt id to raw interrupt payload.

        Returns:
            Resume values keyed by interrupt id.

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Ensure the HooksRuntime is attached to the manager (build/set the runtime via _build_service's configuration path) before resuming
  2. Complete runtime initialization before calling execute/fulfill paths — hooks require the client hook service to be configured
  3. If hooks are intentionally unused, clear the pending hook interrupts instead of fulfilling them
  4. Check process startup/config so the hook runtime is constructed in the same process that fulfills interrupts

Example fix

// before
manager = HookManager(...)  # no runtime attached
await manager.fulfill_interrupt(payload)

// after
manager = HookManager(...)
manager.set_runtime(HooksRuntime(config=hook_config))  # attach runtime first
await manager.fulfill_interrupt(payload)
Defensive patterns

Strategy: fallback

Validate before calling

if manager._runtime is None:  # prefer a public accessor if available
    raise RuntimeError("hooks runtime not initialized; cannot fulfill hook interrupt")

Type guard

def can_fulfill_hooks(manager) -> bool:
    return manager._runtime is not None

Try / catch

try:
    resume = await manager.fulfill_interrupt(payload)
except RuntimeError as exc:
    if "without a HooksRuntime" in str(exc):
        manager.set_runtime(build_hooks_runtime(hook_config))
        resume = await manager.fulfill_interrupt(payload)
    else:
        raise

Prevention

When it happens

Trigger: Calling fulfill_interrupt (e.g. from execute_task_textual) on a HookManager whose HooksRuntime was never attached — such as a manager created before runtime initialization, or one running in a mode where hooks are disabled.

Common situations: Resuming an agent graph that contains pending hook interrupts while the client-side runtime isn't wired (misconfiguration, runtime not started, or a long-lived manager whose runtime was closed); replaying persisted thread state with hook interrupts in a fresh process where hooks weren't configured.

Related errors


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