{"record":{"id":"f8192a596fd56f43","repo":"langchain-ai/deepagents","slug":"expected-userpromptsubmitdecision-got-type-decis","errorCode":null,"errorMessage":"Expected UserPromptSubmitDecision, got {type(decision).__name__}","messagePattern":"Expected UserPromptSubmitDecision, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/hooks/client_lifecycle.py","lineNumber":219,"sourceCode":"\n        Returns:\n            Aggregated prompt decision.\n\n        Raises:\n            TypeError: If the runtime returns a mismatched decision type.\n        \"\"\"\n        if not self.has_handlers(HookEvent.USER_PROMPT_SUBMIT):\n            return UserPromptSubmitDecision(event=HookEvent.USER_PROMPT_SUBMIT)\n        decision = await self._invoke(\n            context,\n            UserPromptSubmitEvent(\n                event=HookEvent.USER_PROMPT_SUBMIT,\n                prompt=prompt,\n            ),\n        )\n        if not isinstance(decision, UserPromptSubmitDecision):\n            msg = f\"Expected UserPromptSubmitDecision, got {type(decision).__name__}\"\n            raise TypeError(msg)\n        return decision\n\n    async def pre_compact(\n        self,\n        context: ClientHookContext,\n        trigger: CompactTrigger,\n        *,\n        custom_instructions: str = \"\",\n    ) -> PreCompactDecision:\n        \"\"\"Invoke `PreCompact` through the session hook runtime.\n\n        Args:\n            context: Current client turn context.\n            trigger: Manual or automatic compaction source.\n            custom_instructions: Optional compaction instructions.\n\n        Returns:\n            Aggregated pre-compaction decision.","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/hooks/client_lifecycle.py#L201-L237","documentation":"ClientHookService.user_prompt_submit validates that the decision object returned by the client-side hook handler is an instance of UserPromptSubmitDecision. If a registered hook callable returns anything else (a plain dict, None, a string, or a wrong Decision type), the service refuses to propagate it and raises TypeError. This guards the typed Hooks v2 contract so downstream agent logic can rely on a well-formed decision.","triggerScenarios":"Calling user_prompt_submit() (or on_user_prompt on the manager) when a registered USER_PROMPT_SUBMIT hook returns a non-UserPromptSubmitDecision value — e.g. returning {'behavior': 'allow'} dict instead of UserPromptSubmitDecision.allow(), returning None, or returning a Decision type from a different hook event.","commonSituations":"Hand-written hook callbacks written before the typed Decision classes existed; hooks shared across events where one callback returns the wrong decision type; deserializing decisions from JSON without running them through the pydantic adapter; typos like returning UserPromptSubmitDecision for a different event's decision class.","solutions":["Return a UserPromptSubmitDecision instance from the hook (e.g. UserPromptSubmitDecision.allow() or .block(reason=...)) instead of a dict or None","If the hook returns raw data, validate/convert it with the library's pydantic adapter (e.g. UserPromptSubmitDecision.model_validate(raw)) before returning","Check that the callback registered for USER_PROMPT_SUBMIT is not a generic handler reused from another event","Update custom hook wrappers to the current typed Hooks v2 API if upgrading from an older version"],"exampleFix":"// before\ndef my_hook(context, event):\n    return {\"behavior\": \"allow\"}\n\n// after\nfrom deepagents_code.hooks import UserPromptSubmitDecision\n\ndef my_hook(context, event):\n    return UserPromptSubmitDecision.allow()","handlingStrategy":"type-guard","validationCode":"from deepagents_code.hooks import UserPromptSubmitDecision\n\nresult = my_hook(context, event)\nif not isinstance(result, UserPromptSubmitDecision):\n    result = UserPromptSubmitDecision.model_validate(result)\n","typeGuard":"def is_user_prompt_decision(value: object) -> bool:\n    return isinstance(value, UserPromptSubmitDecision)\n","tryCatchPattern":"try:\n    decision = await service.user_prompt_submit(context, prompt)\nexcept TypeError as exc:\n    logger.warning(\"hook returned invalid decision: %s\", exc)\n    decision = UserPromptSubmitDecision.allow()\n","preventionTips":["Always return typed Decision objects, never raw dicts, from hook callbacks","Convert deserialized hook data with model_validate before returning","Keep one callback per hook event to avoid returning the wrong decision class"],"tags":["hooks","type-validation","typeerror"],"backgroundTag":"hook-decision-type-mismatch","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}