langchain-ai/deepagents · error · ClientHookStopError
Compact session start stopped by hook
Error message
Compact session start stopped by hook
What it means
After a headless compaction, `_after_headless_compact` fires `on_session_start` with cause `COMPACT`; if the hook outcome is not ok, it raises `ClientHookStopError` using the hook's `stop_reason` or this default message. This lets hooks veto continuing the session after context compaction.
Source
Thrown at libs/code/deepagents_code/client/non_interactive.py:1989
isinstance(message, ToolMessage)
and getattr(message, "name", None) == "compact_conversation"
and str(message.content).startswith("Conversation compacted.")
):
return None
tool_call_id = getattr(message, "tool_call_id", None)
return tool_call_id if isinstance(tool_call_id, str) and tool_call_id else None
async def _after_headless_compact(state: StreamState) -> None:
from deepagents_code.hooks.client_lifecycle import ClientHookStopError
from deepagents_code.hooks.models.domain import SessionStartCause
outcome = await state.hooks.on_session_start(
SessionStartCause.COMPACT,
model=state.active_model,
)
if not outcome.ok:
raise ClientHookStopError(
outcome.stop_reason or "Compact session start stopped by hook"
)
async def _end_headless_session(
state: StreamState,
cause: SessionEndCause,
*,
timeout_seconds: float = SESSION_END_DRAIN_TIMEOUT_SECONDS,
) -> None:
"""End a headless session without letting Hooks v2 stall process exit.
Args:
state: Active headless stream state.
cause: Reason the session ended.
timeout_seconds: Maximum time to wait for `SessionEnd` handlers.
"""
if state.session_end_fired:View on GitHub (pinned to a1af029e6e)
Solutions
- Inspect the hook's `stop_reason`; if you only see the default text, identify the hook handling `SessionStartCause.COMPACT` and fix or disable it.
- Handle the COMPACT cause explicitly in the hook and return ok when continuation is intended.
- Catch `ClientHookStopError` around the headless run and finalize session state via the session-end path.
- Test hooks against all `SessionStartCause` values (STARTUP, COMPACT).
Example fix
// before
async def on_session_start(cause, model): return HookOutcome(ok=False)
// after
async def on_session_start(cause, model):
if cause is SessionStartCause.COMPACT:
return HookOutcome(ok=True)
return check_policy(model) Defensive patterns
Strategy: try-catch
Try / catch
from deepagents_code.hooks.client_lifecycle import ClientHookStopError
try:
await _stream_agent(...)
except ClientHookStopError as exc:
if not exc.args[0] or exc.args[0] == "Compact session start stopped by hook":
find_hook_missing_compact_handling() # hook returned not-ok without a reason Prevention
- Handle `SessionStartCause.COMPACT` explicitly in every session-start hook
- Always set `stop_reason` when returning ok=False
- Exercise compaction in hook integration tests
When it happens
Trigger: A compaction occurs during `_stream_agent` and a registered client hook returns `ok=False` from `on_session_start(SessionStartCause.COMPACT)` without a `stop_reason`, producing this default message.
Common situations: Budget or policy hooks rejecting post-compaction continuation; hooks that only allow fresh sessions (not COMPACT restarts); a hook implementation bug returning not-ok on the COMPACT cause it did not handle.
Related errors
- Session start stopped by hook
- Compact session start stopped by hook
- {message}
- Permission interrupted by hook
- Offload server returned an invalid operation response.
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/5225035ee654811b.
Report an issue: GitHub.