{"record":{"id":"fea8d63c2be05eab","repo":"langchain-ai/deepagents","slug":"async-subagent-name-has-no-url-configured-asg","errorCode":null,"errorMessage":"Async subagent '{name}' has no url configured. ASGI transport (url=None) requires async invocation.","messagePattern":"Async subagent '(.+?)' has no url configured\\. ASGI transport \\(url=None\\) requires async invocation\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/deepagents/deepagents/middleware/async_subagents.py","lineNumber":216,"sourceCode":"\nclass _ClientCache:\n    \"\"\"Lazily-created, cached Agent Protocol clients keyed by (url, headers).\"\"\"\n\n    def __init__(self, agents: dict[str, AsyncSubAgent]) -> None:\n        self._agents = agents\n        self._sync: dict[tuple[str | None, frozenset[tuple[str, str]]], SyncLangGraphClient] = {}\n        self._async: dict[tuple[str | None, frozenset[tuple[str, str]]], LangGraphClient] = {}\n\n    def _cache_key(self, spec: AsyncSubAgent) -> tuple[str | None, frozenset[tuple[str, str]]]:\n        \"\"\"Build a cache key from the agent spec's url and resolved headers.\"\"\"\n        return (spec.get(\"url\"), frozenset(_resolve_headers(spec).items()))\n\n    def get_sync(self, name: str) -> SyncLangGraphClient:\n        \"\"\"Get or create a sync client for the named agent.\"\"\"\n        spec = self._agents[name]\n        if spec.get(\"url\") is None:\n            msg = f\"Async subagent '{name}' has no url configured. ASGI transport (url=None) requires async invocation.\"\n            raise ValueError(msg)\n        key = self._cache_key(spec)\n        if key not in self._sync:\n            self._sync[key] = get_sync_client(\n                url=spec.get(\"url\"),\n                headers=_resolve_headers(spec),\n            )\n        return self._sync[key]\n\n    def get_async(self, name: str) -> LangGraphClient:\n        \"\"\"Get or create an async client for the named agent.\"\"\"\n        spec = self._agents[name]\n        key = self._cache_key(spec)\n        if key not in self._async:\n            self._async[key] = get_client(\n                url=spec.get(\"url\"),\n                headers=_resolve_headers(spec),\n            )\n        return self._async[key]","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/deepagents/deepagents/middleware/async_subagents.py#L198-L234","documentation":"AsyncSubAgentsMiddleware's ClientManager raises this when get_sync() is asked for a sync LangGraph client for an async subagent whose spec has no 'url'. A spec without a url uses ASGI in-process transport, which only works with async clients; a sync client cannot be created. This guards call paths that synchronously poll subagent state (status checks, cancels, live fetches).","triggerScenarios":"Calling check_async_task, update_async_task, cancel_async_task, or _fetch_live_status (which call get_sync) for a subagent defined with no 'url' key (ASGI transport); get_sync itself is public so calling it directly with a url-less spec also triggers.","commonSituations":"Defining async subagents as in-process graphs (url omitted) and then having the agent synchronously poll or cancel the task; mixing sync tool paths with ASGI-transport subagents; typos like 'urls' or 'base_url' in the subagent spec.","solutions":["Configure an httpx/HTTP URL in the subagent spec so sync polling is possible","Use the async variants (await check_async_task/cancel_async_task) which use the ASGI-capable async client instead of get_sync","Only start async tasks for url-backed subagents if you plan to sync-poll them"],"exampleFix":"// before\nasync_subagents=[{\"name\": \"researcher\", \"graph\": \"researcher\"}]\n// after\nasync_subagents=[{\"name\": \"researcher\", \"url\": \"http://localhost:8123\"}]","handlingStrategy":"validation","validationCode":"def can_sync_poll(spec: dict) -> bool:\n    return spec.get(\"url\") is not None","typeGuard":null,"tryCatchPattern":"try:\n    client = clients.get_sync(name)\nexcept ValueError as e:\n    # fall back to async status path or skip polling\n    logger.warning(\"sync poll unavailable: %s\", e)","preventionTips":["Always set a 'url' for subagents you intend to poll synchronously","Use async tool variants for ASGI (url-less) subagents","Validate specs at startup: every spec has either url or is only used async"],"tags":["python","langgraph","async","configuration"],"backgroundTag":"asgi-transport-requires-async","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}