{"record":{"id":"a597b162093340c7","repo":"langchain-ai/langchain","slug":"expected-a-generator-function-type-for-transform","errorCode":null,"errorMessage":"Expected a generator function type for `transform`.Instead got an unsupported type: {type(transform)}","messagePattern":"Expected a generator function type for `transform`\\.Instead got an unsupported type: (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/runnables/base.py","lineNumber":4515,"sourceCode":"\n        \"\"\"\n        func_for_name: Callable[..., Any]\n        if atransform is not None:\n            self._atransform = atransform\n            func_for_name = atransform\n\n        if is_async_generator(transform):\n            self._atransform = transform\n            func_for_name = transform\n        elif inspect.isgeneratorfunction(transform):\n            self._transform = transform\n            func_for_name = transform\n        else:\n            msg = (\n                \"Expected a generator function type for `transform`.\"\n                f\"Instead got an unsupported type: {type(transform)}\"\n            )\n            raise TypeError(msg)\n\n        try:\n            self.name = name or func_for_name.__name__\n        except AttributeError:\n            self.name = \"RunnableGenerator\"\n\n    @property\n    @override\n    def InputType(self) -> Any:\n        func = getattr(self, \"_transform\", None) or self._atransform\n        try:\n            params = inspect.signature(func).parameters\n            first_param = next(iter(params.values()), None)\n            if first_param and first_param.annotation != inspect.Parameter.empty:\n                return getattr(first_param.annotation, \"__args__\", (Any,))[0]\n        except ValueError:\n            pass\n        return Any","sourceCodeStart":4497,"sourceCodeEnd":4533,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/runnables/base.py#L4497-L4533","documentation":"`RunnableGenerator` wraps a transform that must be either a sync generator function (`def f(input: Iterator[X]) -> Iterator[Y]` with `yield`) or an async generator function (`async def ... yield`). Passing a plain function, a coroutine function, or a non-function value fails the type checks and raises a `TypeError` at construction time. The class exists specifically to lazily stream chunks, so a non-generator transform has no streaming semantics to wrap.","triggerScenarios":"`RunnableGenerator(regular_function)`; `RunnableGenerator(async_regular_function)` (a coroutine, not an async generator); `RunnableGenerator(lambda chunks: [f(c) for c in chunks])` (returns a list, no `yield`); passing a callable object that is not a function.","commonSituations":"Migrating from `RunnableLambda` to `RunnableGenerator` and forgetting to add `yield`; writing `async def transform(x): return ...` instead of `async def transform(x): yield ...`; wrapping an existing map-style helper.","solutions":["Make the transform a generator: accept an iterator and `yield` results per chunk.","For async use, write an `async def` transform containing `yield` (an async generator).","If the function cannot stream, use `RunnableLambda` instead of `RunnableGenerator`.","Verify with `inspect.isgeneratorfunction(f)` or `is_async_generator(f)` before constructing."],"exampleFix":"// before\ndef double_all(chunks):\n    return [c * 2 for c in chunks]\nrg = RunnableGenerator(double_all)  # TypeError\n\n// after\ndef double_all(chunks):\n    for c in chunks:\n        yield c * 2\nrg = RunnableGenerator(double_all)","handlingStrategy":"type-guard","validationCode":"import inspect\nfrom langchain_core.runnables.utils import is_async_generator\n\ndef is_generator_transform(fn) -> bool:\n    return inspect.isgeneratorfunction(fn) or is_async_generator(fn)","typeGuard":"import inspect\n\ndef is_sync_generator_function(fn) -> bool:\n    return inspect.isgeneratorfunction(fn)","tryCatchPattern":"try:\n    rg = RunnableGenerator(transform)\nexcept TypeError as e:\n    if 'unsupported type' in str(e):\n        # convert fn into a generator or use RunnableLambda\n        raise\n    raise","preventionTips":["Always write transforms with `yield` (or `async def` + `yield`).","Check with inspect.isgeneratorfunction() when accepting user-supplied transforms.","Use RunnableLambda for non-streaming callables."],"tags":["runnable","runnable-generator","streaming","typeerror"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}