{"record":{"id":"b4977ea4433427c6","repo":"langchain-ai/deepagents","slug":"extension-registration-is-closed-for-this-session","errorCode":null,"errorMessage":"Extension registration is closed for this session","messagePattern":"Extension registration is closed for this session","errorType":"exception","errorClass":"ExtensionError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/extensions/api.py","lineNumber":68,"sourceCode":"            registry: Shared registry receiving extension units.\n            source: Provenance recorded on each registration.\n            cwd: Working directory for this session.\n            mode: Runtime mode, either `interactive` or `headless`.\n        \"\"\"\n        self._registry = registry\n        self._source = source\n        self._cwd = cwd\n        self._mode = ExtensionMode(mode)\n        self._active = True\n\n    def _deactivate(self) -> None:\n        \"\"\"Close this registrar after failed initialization or shutdown.\"\"\"\n        self._active = False\n\n    def _ensure_active(self) -> None:\n        if not self._active:\n            msg = \"Extension registration is closed for this session\"\n            raise ExtensionError(msg)\n\n    @property\n    def cwd(self) -> Path:\n        \"\"\"Working directory for this session.\"\"\"\n        return self._cwd\n\n    @property\n    def mode(self) -> ExtensionMode:\n        \"\"\"Runtime mode, either `interactive` or `headless`.\"\"\"\n        return self._mode\n\n    @property\n    def has_ui(self) -> bool:\n        \"\"\"Whether this session has an interactive terminal UI.\"\"\"\n        return self._mode == ExtensionMode.INTERACTIVE\n\n    @property\n    def path(self) -> Path:","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/extensions/api.py#L50-L86","documentation":"Each extension gets an `ExtensionAPI` registrar that is active only during its factory run. After initialization fails or the session shuts down, `_deactivate()` closes the registrar, and every registration method (`register_middleware`, `register_tool`, `register_backend_route`, `on_shutdown`) raises `ExtensionError` via `_ensure_active`. This prevents extensions from mutating a registry that is no longer live.","triggerScenarios":"Calling any `register_*` method or `on_shutdown` from a background thread/async task after the factory returned; keeping a reference to the registrar and registering during a later shutdown hook; reusing a cached registrar instance across sessions.","commonSituations":"Extensions that spawn worker threads which lazily register tools on first use; extensions registering in `atexit`-style cleanup; retry logic that re-invokes the factory's returned registrar after a failed init.","solutions":["Perform all registrations synchronously inside the extension factory before returning.","Use `api.on_shutdown(...)` inside the factory to schedule post-shutdown work instead of registering later.","Guard deferred registration attempts with a check for session liveness, or capture desired registrations and apply them in the factory.","If initialization failed, fix the underlying init error and restart the session — the registrar cannot be reopened."],"exampleFix":"# before\nthreading.Timer(5.0, lambda: api.register_tool(tool)).start()\n\n# after\napi.register_tool(tool)  # register before the factory returns\n","handlingStrategy":"try-catch","validationCode":"# inside the extension factory, register everything before returning\ndef activate(api):\n    api.register_tool(my_tool)\n    api.register_middleware(MyMiddleware())\n    api.on_shutdown(cleanup)\n    # do NOT stash `api` for later use\n","typeGuard":"def can_register(api) -> bool:\n    return getattr(api, \"_active\", False)\n","tryCatchPattern":"try:\n    api.register_tool(tool)\nexcept ExtensionError as exc:\n    if \"registration is closed\" in str(exc):\n        logger.error(\"session ended; tool %s was never registered\", tool.name)\n    else:\n        raise\n","preventionTips":["Do all registrations synchronously inside the extension factory.","Never keep or share the registrar reference beyond the factory call.","Use `on_shutdown` for end-of-session work instead of late registration.","Avoid lazy background-thread registration."],"tags":["extensions","lifecycle","registration"],"backgroundTag":"registration-closed","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}