langchain-ai/deepagents · error · ExtensionError
Extension registration is closed for this session
Error message
Extension registration is closed for this session
What it means
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.
Source
Thrown at libs/code/deepagents_code/extensions/api.py:68
registry: Shared registry receiving extension units.
source: Provenance recorded on each registration.
cwd: Working directory for this session.
mode: Runtime mode, either `interactive` or `headless`.
"""
self._registry = registry
self._source = source
self._cwd = cwd
self._mode = ExtensionMode(mode)
self._active = True
def _deactivate(self) -> None:
"""Close this registrar after failed initialization or shutdown."""
self._active = False
def _ensure_active(self) -> None:
if not self._active:
msg = "Extension registration is closed for this session"
raise ExtensionError(msg)
@property
def cwd(self) -> Path:
"""Working directory for this session."""
return self._cwd
@property
def mode(self) -> ExtensionMode:
"""Runtime mode, either `interactive` or `headless`."""
return self._mode
@property
def has_ui(self) -> bool:
"""Whether this session has an interactive terminal UI."""
return self._mode == ExtensionMode.INTERACTIVE
@property
def path(self) -> Path:View on GitHub (pinned to a1af029e6e)
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.
Example fix
# before threading.Timer(5.0, lambda: api.register_tool(tool)).start() # after api.register_tool(tool) # register before the factory returns
Defensive patterns
Strategy: try-catch
Validate before calling
# inside the extension factory, register everything before returning
def activate(api):
api.register_tool(my_tool)
api.register_middleware(MyMiddleware())
api.on_shutdown(cleanup)
# do NOT stash `api` for later use
Type guard
def can_register(api) -> bool:
return getattr(api, "_active", False)
Try / catch
try:
api.register_tool(tool)
except ExtensionError as exc:
if "registration is closed" in str(exc):
logger.error("session ended; tool %s was never registered", tool.name)
else:
raise
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Server process is not running
- A workspace is required to start the remote agent.
- Session start stopped by hook
- UnixSocketEventSource is already started
- UnixSocketEventSource.serve_forever called before start()
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/b4977ea4433427c6.
Report an issue: GitHub.