langchain-ai/deepagents · error · ClientHookStopError
Session start stopped by hook
Error message
Session start stopped by hook
What it means
At the start of `_run_agent_loop`, `on_session_start(SessionStartCause.STARTUP)` runs; if the hook outcome is not ok, the session is ended with `SessionEndCause.OTHER` and `ClientHookStopError` is raised with the hook's `stop_reason` or this default message. Client hooks therefore have veto power over starting a headless session.
Source
Thrown at libs/code/deepagents_code/client/non_interactive.py:2239
# Project hooks require an explicit opt-in, matching `--trust-project-mcp`.
# Persisted interactive trust deliberately does not carry into headless
# runs, so CI never inherits a grant made at someone's terminal.
trust=WorkspaceTrust.explicit_only(Path.cwd(), granted=trust_project_hooks),
)
state.hooks.attach_output(notice=present_hook_notice, status=hook_status)
state.hooks.apply_graph_context(context)
context["approval_mode"] = resolved_approval_mode.value
context["auto_approve"] = resolved_approval_mode is ApprovalMode.YOLO
state.active_model = runtime_state.model_name or None
state.transcript = state.hooks.recorder(thread_id)
start_outcome = await state.hooks.on_session_start(
SessionStartCause.STARTUP,
model=runtime_state.model_name or None,
)
if not start_outcome.ok:
await _end_headless_session(state, SessionEndCause.OTHER)
raise ClientHookStopError(
start_outcome.stop_reason or "Session start stopped by hook"
)
session_context = state.hooks.take_pending_context()
if session_context:
stream_input["messages"].insert(
0,
{"role": "system", "content": "\n\n".join(session_context)},
)
try:
state.transcript.append([HumanMessage(content=message)])
if state.hooks.has_handlers(HookEvent.USER_PROMPT_SUBMIT):
prompt_outcome = await state.hooks.on_user_prompt(message)
if not prompt_outcome.ok:
_raise_client_hook_stop(
prompt_outcome.stop_reason
or "User prompt submission stopped by hook"
)View on GitHub (pinned to a1af029e6e)
Solutions
- Read `stop_reason` from the error; fix the condition in the hook that rejected startup.
- Adjust hook configuration (model allow-lists, trust settings for project hooks) so legitimate sessions pass.
- Catch `ClientHookStopError` in the caller to handle a deliberate stop gracefully (session state is already ended via `_end_headless_session`).
- If no hook should be active, check that hooks aren't being loaded unintentionally (project hook trust opt-in).
Example fix
// before: hook blocks everything not on an old list
if model not in ["old-model"]: return HookOutcome(ok=False, stop_reason="model blocked")
// after: keep list current
if model not in APPROVED_MODELS: return HookOutcome(ok=False, stop_reason=f"model {model} not approved") Defensive patterns
Strategy: try-catch
Try / catch
from deepagents_code.hooks.client_lifecycle import ClientHookStopError
try:
run_non_interactive(task)
except ClientHookStopError as exc:
# session already ended with SessionEndCause.OTHER; surface the hook's reason
report_session_blocked(exc) Prevention
- Keep hook model/policy allow-lists current
- Review project-hook trust settings before headless runs
- Return meaningful stop_reason values from hooks for diagnosability
When it happens
Trigger: Calling `run_non_interactive` (which enters `_run_agent_loop`) while a registered client lifecycle hook rejects the startup cause — e.g. policy checks on model name, environment, or repository.
Common situations: Org guardrail hooks blocking untrusted project hooks or disallowed models; hooks failing environment validation in CI; tests asserting that a user-prompt stop or untrusted project hooks end the session once.
Related errors
- Compact session start stopped by hook
- User prompt submission stopped by hook
- Compact session start stopped by hook
- Server process is not running
- A workspace is required to start the remote agent.
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/ad9b5fc35a30e599.
Report an issue: GitHub.