{"record":{"id":"0c20e5f5c2ae71e6","repo":"langchain-ai/deepagents","slug":"registered-middleware-must-be-an-agentmiddleware","errorCode":null,"errorMessage":"Registered middleware must be an AgentMiddleware, got {kind}","messagePattern":"Registered middleware must be an AgentMiddleware, got (.+?)","errorType":"validation","errorClass":"ExtensionError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/extensions/api.py","lineNumber":116,"sourceCode":"\n        Args:\n            middleware: Middleware class or instance.\n\n        Raises:\n            ExtensionError: If `middleware` is invalid or cannot be constructed.\n        \"\"\"\n        self._ensure_active()\n        from langchain.agents.middleware.types import AgentMiddleware\n\n        try:\n            instance = middleware() if isinstance(middleware, type) else middleware\n        except Exception as exc:\n            msg = f\"Could not construct middleware {middleware!r}: {exc}\"\n            raise ExtensionError(msg) from exc\n        if not isinstance(instance, AgentMiddleware):\n            kind = type(instance).__name__\n            msg = f\"Registered middleware must be an AgentMiddleware, got {kind}\"\n            raise ExtensionError(msg)\n        self._registry.add_middleware(instance, self._source)\n\n    def register_tool(self, tool: BaseTool | Callable[..., Any]) -> None:\n        \"\"\"Expose an LLM-callable tool.\n\n        Plain callables are converted using LangChain's tool schema inference.\n\n        Args:\n            tool: Tool instance or plain callable.\n\n        Raises:\n            ExtensionError: If a callable cannot be converted into a tool.\n        \"\"\"\n        self._ensure_active()\n        from langchain_core.tools import BaseTool, tool as as_tool\n\n        if isinstance(tool, BaseTool):\n            self._registry.add_tool(tool, self._source)","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/extensions/api.py#L98-L134","documentation":"After constructing the value, `register_middleware` verifies the instance is an `AgentMiddleware` (checked at runtime against `langchain.agents.middleware.types.AgentMiddleware`). Anything else — a plain object, a callable, a tool, or a wrapper — is rejected with `ExtensionError` naming the offending type. This keeps only contract-compliant middleware on the agent.","triggerScenarios":"Registering an arbitrary object or function that duck-types middleware but does not subclass `AgentMiddleware`; passing a `BaseTool` or callable to `register_middleware` instead of `register_tool`; inheriting from the wrong base class after a LangChain refactor.","commonSituations":"Confusion between `register_tool` and `register_middleware` when wiring custom hooks; custom middleware extending a deprecated base whose class no longer subclasses `AgentMiddleware`; LangChain version upgrade moving/renaming the middleware hierarchy.","solutions":["Subclass `AgentMiddleware` from `langchain.agents.middleware.types` for custom middleware.","Use `api.register_tool(...)` for tools/callables, not `register_middleware`.","Verify `isinstance(obj, AgentMiddleware)` in the extension before registering; update the langchain pin if the base class moved.","If wrapping a third-party object, adapt it into an `AgentMiddleware` subclass."],"exampleFix":"# before\nclass MyHook:\n    ...\napi.register_middleware(MyHook())\n\n# after\nfrom langchain.agents.middleware.types import AgentMiddleware\nclass MyHook(AgentMiddleware):\n    ...\napi.register_middleware(MyHook())\n","handlingStrategy":"type-guard","validationCode":"from langchain.agents.middleware.types import AgentMiddleware\n\ndef assert_agent_middleware(obj) -> None:\n    if not isinstance(obj, AgentMiddleware):\n        raise TypeError(f\"{type(obj).__name__} is not an AgentMiddleware\")\n","typeGuard":"def is_agent_middleware(obj) -> bool:\n    return isinstance(obj, AgentMiddleware)\n","tryCatchPattern":"try:\n    api.register_middleware(candidate)\nexcept ExtensionError as exc:\n    if \"must be an AgentMiddleware\" in str(exc):\n        logger.error(\"wrong registration API for %s; use register_tool for tools\", candidate)\n    else:\n        raise\n","preventionTips":["Subclass `AgentMiddleware` for anything registered as middleware.","Route tools and callables through `register_tool`, not `register_middleware`.","Add an isinstance assert in tests for every registered middleware.","Re-verify middleware bases after LangChain version upgrades."],"tags":["extensions","middleware","type-check"],"backgroundTag":"middleware-type-mismatch","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}