{"record":{"id":"6b91a4181896fe25","repo":"langchain-ai/deepagents","slug":"hooks-snapshot-id-is-required-to-emit-server-owned","errorCode":null,"errorMessage":"hooks_snapshot_id is required to emit server-owned hook events","messagePattern":"hooks_snapshot_id is required to emit server-owned hook events","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/hooks/server_middleware.py","lineNumber":912,"sourceCode":"    context: HookContext,\n    event: (\n        PreToolUseEvent\n        | PostToolUseEvent\n        | PostToolUseFailureEvent\n        | PreCompactEvent\n        | StopEvent\n        | SubagentStartEvent\n        | SubagentStopEvent\n    ),\n    *,\n    gate: _SessionHookGate | None,\n    config: Mapping[str, Any] | None,\n    deadline: timedelta,\n    logical_event_id: str | None = None,\n) -> HookDecision:\n    if gate is None:\n        msg = \"hooks_snapshot_id is required to emit server-owned hook events\"\n        raise RuntimeError(msg)\n    run_id = _run_id(config, context.thread_id)\n    invocation_id = _invocation_id(\n        snapshot_id=gate[\"snapshot_id\"],\n        context=context,\n        event=event,\n        logical_event_id=logical_event_id,\n    )\n    request = HookInvocationRequest(\n        protocol_version=1,\n        invocation_id=invocation_id,\n        snapshot_id=gate[\"snapshot_id\"],\n        run_id=run_id,\n        invocation=HookInvocation(context=context, event=event),\n        deadline=datetime.now(UTC) + deadline,\n    )\n    operation_responses = _HOOK_RESPONSES.get()\n    if operation_responses is None:\n        raw = interrupt(build_hook_interrupt_payload(request))","sourceCodeStart":894,"sourceCodeEnd":930,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/hooks/server_middleware.py#L894-L930","documentation":"Server-owned hook events (progress, audit) are keyed by a hooks_snapshot_id carried in the session gate/context. Without it the middleware cannot attribute emitted events to a validated hook snapshot, so _invoke_hook raises RuntimeError rather than emitting events with unknown provenance. This indicates the middleware was driven outside a properly snapshot-initialized session.","triggerScenarios":"Calling _invoke_hook (via any of _maybe_subagent_start, _after_model, _maybe_post_tool_use, _maybe_subagent_stop, _after_agent, _pre_auto_compact) when the resolved session gate is None — i.e. the runtime context/config carries no hooks_snapshot_id field.","commonSituations":"Invoking the agent graph directly with a hand-built config that omits hooks snapshot metadata; running a stale client against a newer server that requires snapshot ids; constructing the middleware without going through the snapshot-creation entry point.","solutions":["Ensure the agent is created/run through the standard entry point that builds a hook snapshot and injects hooks_snapshot_id into the runtime context (e.g. the server session bootstrap).","If constructing config manually, include the hooks_snapshot_id produced by HooksSnapshot.from_config/create in the context fields.","Update client/server together so both sides agree on snapshot propagation.","Catch RuntimeError during development and assert gate presence to fail fast on misconfiguration."],"exampleFix":"// before\nconfig = {\"configurable\": {\"thread_id\": tid}}\nagent.invoke(state, config)  # RuntimeError: no hooks_snapshot_id\n\n// after\nsnapshot = HooksSnapshot.create(config_with_hooks)\nconfig = {\"configurable\": {\"thread_id\": tid, \"hooks_snapshot_id\": snapshot.snapshot_id}}\nagent.invoke(state, config)","handlingStrategy":"validation","validationCode":"gate = _session_gate(runtime_context)\nif gate is None or not gate.get(\"snapshot_id\"):\n    raise RuntimeError(\"run agent through a snapshot-initialized session\")","typeGuard":"def has_hooks_snapshot(context: Mapping[str, Any]) -> TypeGuard[Mapping[str, Any]]:\n    return isinstance(context.get(\"hooks_snapshot_id\"), str) and bool(context[\"hooks_snapshot_id\"])","tryCatchPattern":"try:\n    agent.invoke(state, config)\nexcept RuntimeError as exc:\n    if \"hooks_snapshot_id\" in str(exc):\n        reinitialize_session_with_snapshot()","preventionTips":["Create agents via the standard bootstrap that builds a HooksSnapshot","Never hand-build runtime context without hooks_snapshot_id when hooks are enabled","Keep client and server versions in sync","Assert snapshot presence in integration tests"],"tags":["hooks","session","runtime-error"],"backgroundTag":"missing-hooks-snapshot-id","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}