{"record":{"id":"c07df5f71db9e11c","repo":"langchain-ai/langchain","slug":"self-r-only-supports-sync-methods","errorCode":null,"errorMessage":"{self!r} only supports sync methods.","messagePattern":"(.+?) only supports sync methods\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/runnables/base.py","lineNumber":4663,"sourceCode":"    @override\n    def invoke(\n        self, input: Input, config: RunnableConfig | None = None, **kwargs: Any\n    ) -> Output:\n        final: Output | None = None\n        for output in self.stream(input, config, **kwargs):\n            final = output if final is None else final + output  # type: ignore[operator]\n        return cast(\"Output\", final)\n\n    @override\n    def atransform(\n        self,\n        input: AsyncIterator[Input],\n        config: RunnableConfig | None = None,\n        **kwargs: Any,\n    ) -> AsyncIterator[Output]:\n        if not hasattr(self, \"_atransform\"):\n            msg = f\"{self!r} only supports sync methods.\"\n            raise NotImplementedError(msg)\n\n        return self._atransform_stream_with_config(\n            input, self._atransform, config, defers_inputs=True, **kwargs\n        )\n\n    @override\n    def astream(\n        self,\n        input: Input,\n        config: RunnableConfig | None = None,\n        **kwargs: Any,\n    ) -> AsyncIterator[Output]:\n        async def input_aiter() -> AsyncIterator[Input]:\n            yield input\n\n        return self.atransform(input_aiter(), config, **kwargs)\n\n    @override","sourceCodeStart":4645,"sourceCodeEnd":4681,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/runnables/base.py#L4645-L4681","documentation":"`RunnableGenerator.atransform` requires an async `_atransform`, set only when the constructor received an async generator function. If the generator wraps a sync generator, the async path is absent and `.astream()`/`.atransform()` raises `NotImplementedError`. Sync generator code cannot be safely driven inside an event loop's async iteration protocol by this class.","triggerScenarios":"`RunnableGenerator(sync_generator)` then `async for chunk in rg.astream(x)` or `await rg.atransform(...)`; also `await rg.ainvoke(x)` since it consumes the async stream.","commonSituations":"Reusing a sync streaming transformer inside an async FastAPI/LangServe endpoint; upgrading a sync pipeline to `asyncio` without rewriting the generator.","solutions":["Call the sync API from a worker: `await run_in_executor(None, lambda: list(rg.stream(x)))`.","Rewrite the transform as an async generator (`async def` + `yield`, `async for` over input).","Run sync streaming in a thread and bridge chunks via an `asyncio.Queue` if you need true async streaming.","Standardize team code on async generators for anything used in async servers."],"exampleFix":"// before\ndef transform(chunks):\n    for c in chunks:\n        yield c * 2\nrg = RunnableGenerator(transform)\nasync for c in rg.astream([1]):  # NotImplementedError\n    ...\n\n// after\nasync def atransform(chunks):\n    async for c in chunks:\n        yield c * 2\nrg = RunnableGenerator(atransform)\nasync for c in rg.astream([1]):\n    ...","handlingStrategy":"fallback","validationCode":"def supports_async_stream(rg) -> bool:\n    return hasattr(rg, '_atransform')","typeGuard":"def is_async_generator_runnable(rg) -> bool:\n    return hasattr(rg, '_atransform')","tryCatchPattern":"try:\n    async for chunk in rg.astream(x):\n        ...\nexcept NotImplementedError as e:\n    if 'only supports sync' in str(e):\n        chunks = await asyncio.to_thread(lambda: list(rg.stream(x)))\n    else:\n        raise","preventionTips":["Write async generator transforms for anything used in async servers.","Bridge sync generators with asyncio.to_thread instead of calling astream.","Tag runnables with their supported execution mode in team conventions."],"tags":["runnable","runnable-generator","sync-async-mismatch","streaming","asyncio"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}