{"record":{"id":"559732967c5b1c48","repo":"langchain-ai/langchain","slug":"self-r-only-supports-async-methods","errorCode":null,"errorMessage":"{self!r} only supports async methods.","messagePattern":"(.+?) only supports async methods\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/runnables/base.py","lineNumber":4627,"sourceCode":"            return False\n        return False\n\n    __hash__ = None  # type: ignore[assignment]\n\n    @override\n    def __repr__(self) -> str:\n        return f\"RunnableGenerator({self.name})\"\n\n    @override\n    def transform(\n        self,\n        input: Iterator[Input],\n        config: RunnableConfig | None = None,\n        **kwargs: Any,\n    ) -> Iterator[Output]:\n        if not hasattr(self, \"_transform\"):\n            msg = f\"{self!r} only supports async methods.\"\n            raise NotImplementedError(msg)\n        return self._transform_stream_with_config(\n            input,\n            self._transform,  # type: ignore[arg-type]\n            config,\n            defers_inputs=True,\n            **kwargs,\n        )\n\n    @override\n    def stream(\n        self,\n        input: Input,\n        config: RunnableConfig | None = None,\n        **kwargs: Any,\n    ) -> Iterator[Output]:\n        return self.transform(iter([input]), config, **kwargs)\n\n    @override","sourceCodeStart":4609,"sourceCodeEnd":4645,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/runnables/base.py#L4609-L4645","documentation":"`RunnableGenerator.transform` (the sync streaming path) requires a sync `_transform`, which is only set when the constructor received a sync generator function. If the generator was created with an async transform, only `_atransform` exists, so calling `.stream()`/`.transform()`/`.invoke()` raises `NotImplementedError`. Async-only generators cannot be driven from synchronous code.","triggerScenarios":"`RunnableGenerator(async_transform)` where `async_transform` is an `async def` with `yield`, then calling `.stream(input)`, `.transform(iter([input]))`, or `.invoke(input)` (invoke consumes the sync stream).","commonSituations":"Writing an async streaming transformer for an async app and later reusing it in a script/notebook sync path; test suites that call `.invoke()` on runnables that were built async-only.","solutions":["Use the async API: `await runnable.ainvoke(...)`, `async for chunk in runnable.astream(...)`.","Provide both a sync generator and an async generator if you need both paths (`RunnableGenerator` only stores one, so expose two separate instances or a sync one).","In sync-only code, define the transform as a plain generator function.","In shared libraries, branch on `asyncio.get_event_loop().is_running()` or expose explicit sync/async constructors."],"exampleFix":"// before\nasync def atransform(chunks):\n    async for c in chunks:\n        yield c * 2\nrg = RunnableGenerator(atransform)\nlist(rg.stream([1, 2]))  # NotImplementedError\n\n// after\ndef transform(chunks):\n    for c in chunks:\n        yield c * 2\nrg = RunnableGenerator(transform)\nlist(rg.stream([1, 2]))  # ok\n// or keep async and call: async for chunk in rg.astream([1, 2]): ...","handlingStrategy":"type-guard","validationCode":"import inspect\nfrom langchain_core.runnables import RunnableGenerator\n\ndef supports_sync_stream(rg: RunnableGenerator) -> bool:\n    return inspect.isgeneratorfunction(getattr(rg, '_transform', None)) if hasattr(rg, '_transform') else False","typeGuard":"def is_sync_generator_runnable(rg) -> bool:\n    return hasattr(rg, '_transform')","tryCatchPattern":"try:\n    chunks = list(rg.stream(x))\nexcept NotImplementedError as e:\n    if 'only supports async' in str(e):\n        chunks = asyncio.run(collect(rg.astream(x)))\n    else:\n        raise","preventionTips":["Provide a sync generator if the runnable will be used from sync code.","Keep sync test suites for sync transforms and async suites for async transforms.","Document runnables as sync-only or async-only at construction."],"tags":["runnable","runnable-generator","sync-async-mismatch","streaming"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}