{"record":{"id":"ec942e25ce50323b","repo":"langchain-ai/deepagents","slug":"deep-agents-graph-does-not-expose-async-invocation","errorCode":null,"errorMessage":"Deep Agents graph does not expose async invocation","messagePattern":"Deep Agents graph does not expose async invocation","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/talon/deepagents_talon/runtime.py","lineNumber":420,"sourceCode":"                last_exc = exc\n                backoff = min(2**attempt, 10)\n                logger.warning(\n                    \"Retryable agent error in conversation %s; retrying in %ds: %s\",\n                    conversation_id,\n                    backoff,\n                    exc,\n                )\n                await asyncio.sleep(backoff)\n        if last_exc is not None:\n            raise last_exc\n        msg = \"agent invocation retry loop exited unexpectedly\"\n        raise RuntimeError(msg)\n\n    def _graph_invoke(self) -> Callable[..., Awaitable[object]]:\n        ainvoke = getattr(self._graph, \"ainvoke\", None)\n        if not callable(ainvoke):\n            msg = \"Deep Agents graph does not expose async invocation\"\n            raise TypeError(msg)\n        return cast(\"Callable[..., Awaitable[object]]\", ainvoke)\n\n    async def _invoke_until_unblocked(\n        self,\n        content: ModelContent,\n        request: AgentRequest,\n    ) -> object:\n        state = await self._invoke_with_retries(content, request.conversation_id)\n        for _ in range(DEFAULT_MAX_APPROVAL_ROUNDS):\n            interrupts = _interrupts_from_state(state)\n            if not interrupts:\n                return state\n            resume = await self._build_approval_resume(request, interrupts)\n            state = await self._resume_with_retries(resume, request.conversation_id)\n        msg = \"agent hit tool approval interrupt limit\"\n        raise RuntimeError(msg)\n\n    async def _build_approval_resume(","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/talon/deepagents_talon/runtime.py#L402-L438","documentation":"_graph_invoke fetches `ainvoke` from the compiled Deep Agents graph and raises this TypeError when the graph object has no callable ainvoke attribute. The runtime only supports async invocation, so a synchronous-only or foreign graph object cannot be used.","triggerScenarios":"Assigning a non-standard object to the runtime's graph (custom graph, mock, or an older LangGraph version lacking `ainvoke`), or stubbing self._graph in tests with a sync fake.","commonSituations":"Version drift where an installed langgraph/deep-agents version compiles a graph without ainvoke; test doubles that only implement invoke(); passing a raw Runnable that only supports sync invoke.","solutions":["Use the graph produced by the library's own start()/build path instead of injecting a custom object","Upgrade langgraph/langchain so the compiled graph exposes `ainvoke`","In tests, make the fake graph implement `async def ainvoke(...)` returning the state"],"exampleFix":"// before\nclass FakeGraph:\n    def invoke(self, *a, **k): ...\nruntime._graph = FakeGraph()\n// after\nclass FakeGraph:\n    async def ainvoke(self, *a, **k):\n        return fake_state\nruntime._graph = FakeGraph()","handlingStrategy":"type-guard","validationCode":"graph = runtime._graph\nif not callable(getattr(graph, \"ainvoke\", None)):\n    raise TypeError(\"runtime graph does not support async invocation; upgrade langgraph\")","typeGuard":"from collections.abc import Awaitable, Callable\n\ndef supports_async_invoke(graph: object) -> bool:\n    return callable(getattr(graph, \"ainvoke\", None))","tryCatchPattern":"try:\n    reply = await runtime.invoke(request)\nexcept TypeError as exc:\n    if \"does not expose async invocation\" in str(exc):\n        raise RuntimeError(\"incompatible graph: upgrade langgraph or use the runtime's own start()\") from exc\n    raise","preventionTips":["Only assign graphs produced by the library's own build/start path","In tests, make fakes implement `async def ainvoke`","Keep langgraph/langchain versions aligned with the library's pins"],"tags":["async","compatibility","graph"],"backgroundTag":"missing-async-api","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}