langchain-ai/deepagents · error · TypeError
Expected {expected.__name__}, got {type(decision).__name__}
Error message
Expected {expected.__name__}, got {type(decision).__name__} What it means
Internal helper _require_decision narrows the generic HookDecision returned by hook execution to the concrete decision type each lifecycle event expects (e.g. SubagentStartDecision, PostToolUseDecision). Hook code that returns a decision object of the wrong concrete class is rejected with TypeError naming the expected and actual types.
Source
Thrown at libs/code/deepagents_code/hooks/server_middleware.py:771
return {_STOP_STATE_KEY: 0}
return None
feedback = "\n".join(decision.feedback).strip() or (
decision.stop_reason or "Continue working."
)
return {
"messages": [HumanMessage(content=feedback)],
"jump_to": "model",
_STOP_STATE_KEY: continuation + 1,
}
def _require_decision[DecisionT: BaseHookDecision](
decision: HookDecision,
expected: type[DecisionT],
) -> DecisionT:
if not isinstance(decision, expected):
msg = f"Expected {expected.__name__}, got {type(decision).__name__}"
raise TypeError(msg)
return decision
def _session_gate(runtime_context: object) -> _SessionHookGate | None:
fields = _context_mapping(runtime_context)
snapshot_id = fields.get("hooks_snapshot_id")
events = fields.get("hooks_server_events")
if not isinstance(snapshot_id, str) or not snapshot_id:
return None
if not isinstance(events, list) or not events:
return None
return {
"snapshot_id": snapshot_id,
"events": frozenset(str(item) for item in events),
}
def _event_enabled(gate: _SessionHookGate | None, event: HookEvent) -> bool:View on GitHub (pinned to a1af029e6e)
Solutions
- Return the decision class matching the event: check the hook event's documented decision type and construct that (e.g. PostToolUseDecision for post-tool-use hooks).
- If a handler serves multiple events, branch inside it on the event and build the correct decision type per event.
- Catch TypeError from agent execution and inspect the message ("Expected X, got Y") to identify which hook returned the wrong type.
- Add type hints on the handler (-> CorrectDecision) so static checkers flag mismatches before runtime.
Example fix
// before
@hooks.on(HookEvent.POST_TOOL_USE)
def guard(event) -> ModelRequestDecision: # wrong decision type
return ModelRequestDecision(approve=True)
// after
@hooks.on(HookEvent.POST_TOOL_USE)
def guard(event) -> PostToolUseDecision:
return PostToolUseDecision(approve=True) Defensive patterns
Strategy: type-guard
Validate before calling
decision = handler(event)
if not isinstance(decision, ExpectedDecision):
raise TypeError(f"{handler} must return {ExpectedDecision.__name__}") Type guard
def is_decision[D: BaseHookDecision](value: object, expected: type[D]) -> TypeGuard[D]:
return isinstance(value, expected) Try / catch
try:
agent.invoke(state, config)
except TypeError as exc:
if str(exc).startswith("Expected ") and "got " in str(exc):
log.error("hook returned wrong decision type", error=str(exc)) Prevention
- Match each event's documented decision class exactly
- Don't share one decision-returning handler across different hook events
- Annotate handler return types and run a static type checker
- Import decision classes carefully to avoid same-named wrong types
When it happens
Trigger: A hook handler registered for one event type returns a decision class belonging to a different event (e.g. returning a ModelRequestDecision from a SubagentStart hook), or a handler returns a BaseHookDecision subclass not matching `expected` in any of the six calling hooks (_maybe_subagent_start, _after_model, _maybe_post_tool_use, _maybe_subagent_stop, _after_agent, _pre_auto_compact).
Common situations: Reusing one handler function across multiple hook events with a single shared decision type; copying an example hook whose decision class doesn't match the registered event; typos in imports pulling the wrong Decision class.
Related errors
- Post-tool hooks must preserve committed ToolMessage results
- context.hooks_server_events must be a list of strings or nul
- hook_responses must be a JSON object.
- -32002
- SHELL_ALLOW_ALL should not be used with ShellAllowListMiddle
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/fa740d92ddd84a31.
Report an issue: GitHub.