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
- Ensure the HooksRuntime is attached to the manager (build/set the runtime via _build_service's configuration path) before resuming
- Complete runtime initialization before calling execute/fulfill paths — hooks require the client hook service to be configured
- If hooks are intentionally unused, clear the pending hook interrupts instead of fulfilling them
- 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
- Initialize and attach the HooksRuntime before executing/resuming any graph that uses hooks
- Use one hook configuration everywhere so interrupts are only raised when a runtime exists
- Add a startup assertion that the runtime is attached when hooks are enabled
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
- Permission interrupted by hook
- Hook resume invocation_id mismatch: expected {invocation_id}
- Hook resume snapshot_id mismatch: expected {snapshot_id}, go
- Failed to parse hook interrupt
- -32600
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/f86831cba8c5a328.
Report an issue: GitHub.