{"record":{"id":"fbb074648cf34804","repo":"langchain-ai/deepagents","slug":"expected-precompactdecision-got-type-decision","errorCode":null,"errorMessage":"Expected PreCompactDecision, got {type(decision).__name__}","messagePattern":"Expected PreCompactDecision, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/hooks/client_lifecycle.py","lineNumber":254,"sourceCode":"        Returns:\n            Aggregated pre-compaction decision.\n\n        Raises:\n            TypeError: If the runtime returns a mismatched decision type.\n        \"\"\"\n        if not self.has_handlers(HookEvent.PRE_COMPACT):\n            return PreCompactDecision(event=HookEvent.PRE_COMPACT)\n        decision = await self._invoke(\n            context,\n            PreCompactEvent(\n                event=HookEvent.PRE_COMPACT,\n                trigger=trigger,\n                custom_instructions=custom_instructions,\n            ),\n        )\n        if not isinstance(decision, PreCompactDecision):\n            msg = f\"Expected PreCompactDecision, got {type(decision).__name__}\"\n            raise TypeError(msg)\n        return decision\n\n    async def permission_request(\n        self,\n        context: ClientHookContext,\n        call: ToolCallData,\n    ) -> PermissionRequestDecision:\n        \"\"\"Invoke `PermissionRequest` before client approval resolution.\n\n        Args:\n            context: Current client session context.\n            call: Tool action awaiting approval.\n\n        Returns:\n            Aggregated permission decision.\n\n        Raises:\n            TypeError: If the runtime returns a mismatched decision type.","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/hooks/client_lifecycle.py#L236-L272","documentation":"ClientHookService.pre_compact validates that the hook handler returned a PreCompactDecision instance before the context-compaction flow continues. Any other return type (dict, None, wrong decision class) raises TypeError. This enforces the typed contract for the pre-compact hook so custom compaction instructions are well-formed.","triggerScenarios":"Calling pre_compact() (or on_pre_compact) when a registered PRE_COMPACT hook returns a plain dict like {'custom_instructions': '...'}, None, or a decision object belonging to another hook event instead of PreCompactDecision.","commonSituations":"Hooks written against an older untyped API; copying a callback from another hook event; constructing the decision with the wrong class name imported from a sibling module; JSON round-trips that lose the concrete type.","solutions":["Return PreCompactDecision (constructed via its allow/custom_instructions helpers or model_validate) from the PRE_COMPACT hook","Convert raw return values with the pydantic adapter before returning them from the hook","Verify the registered callback is specific to the pre-compact event, not shared with other events","Check imports: use the decision class exported for pre_compact, not UserPromptSubmitDecision/NotificationDecision"],"exampleFix":"// before\ndef on_pre_compact(context, event):\n    return {\"custom_instructions\": \"summarize tools\"}\n\n// after\nfrom deepagents_code.hooks import PreCompactDecision\n\ndef on_pre_compact(context, event):\n    return PreCompactDecision(custom_instructions=\"summarize tools\")","handlingStrategy":"type-guard","validationCode":"from deepagents_code.hooks import PreCompactDecision\n\nresult = my_pre_compact_hook(context, event)\nif not isinstance(result, PreCompactDecision):\n    result = PreCompactDecision.model_validate(result)\n","typeGuard":"def is_pre_compact_decision(value: object) -> bool:\n    return isinstance(value, PreCompactDecision)\n","tryCatchPattern":"try:\n    decision = await service.pre_compact(context, trigger, custom_instructions)\nexcept TypeError as exc:\n    logger.warning(\"pre_compact hook returned invalid decision: %s\", exc)\n    decision = PreCompactDecision.allow()\n","preventionTips":["Use the event-specific Decision class for each hook event","Type-annotate hook callbacks with their exact Decision return type so mypy/pyright catches mistakes","Re-validate JSON round-tripped decisions before returning them"],"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"}