{"record":{"id":"7ebf36c3c271be08","repo":"langchain-ai/langchain","slug":"expected-a-runnable-callable-or-dict-instead-got","errorCode":null,"errorMessage":"Expected a Runnable, callable or dict.Instead got an unsupported type: {type(thing)}","messagePattern":"Expected a Runnable, callable or dict\\.Instead got an unsupported type: (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/runnables/base.py","lineNumber":6652,"sourceCode":"    Returns:\n        A `Runnable`.\n\n    Raises:\n        TypeError: If the object is not `Runnable`-like.\n    \"\"\"\n    if isinstance(thing, Runnable):\n        return thing\n    if is_async_generator(thing) or inspect.isgeneratorfunction(thing):\n        return RunnableGenerator(thing)\n    if callable(thing):\n        return RunnableLambda(cast(\"Callable[[Input], Output]\", thing))\n    if isinstance(thing, dict):\n        return RunnableParallel(thing)\n    msg = (\n        f\"Expected a Runnable, callable or dict.\"\n        f\"Instead got an unsupported type: {type(thing)}\"\n    )\n    raise TypeError(msg)\n\n\n@overload\ndef chain(\n    func: Callable[[Input], Coroutine[Any, Any, Output]],\n) -> Runnable[Input, Output]: ...\n\n\n@overload\ndef chain(\n    func: Callable[[Input], Iterator[Output]],\n) -> Runnable[Input, Output]: ...\n\n\n@overload\ndef chain(\n    func: Callable[[Input], AsyncIterator[Output]],\n) -> Runnable[Input, Output]: ...","sourceCodeStart":6634,"sourceCodeEnd":6670,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/runnables/base.py#L6634-L6670","documentation":"Raised by `coerce_to_runnable` in `langchain_core.runnables.base` when the value passed cannot be converted into a `Runnable`. The function only accepts a `Runnable`, an (async) generator function, any other callable (wrapped in `RunnableLambda`), or a dict (wrapped in `RunnableParallel`). Any other type (str, int, list, None, a generator object rather than a generator function, etc.) reaches the fallback `raise TypeError`.","triggerScenarios":"Passing a non-callable, non-dict object anywhere a Runnable is coerced: a `RunnableBranch` condition or branch runnable, `RunnableParallel` values, sequence steps built via `RunnableSequence`/`|`, or `RunnableWithFallbacks(fallbacks=[...])` with a raw string/int/None in the list. Also passing `some_generator()` (an already-consumed generator object) instead of the generator function itself.","commonSituations":"Building a branch or parallel chain from a plain string or constant, e.g. `RunnableBranch((cond, \"done\"), default_fn)`; putting a module path string like `\"my.module.fn\"` instead of the imported function; passing None from an optional lookup; passing a list like `[fn1, fn2]` where a dict `{...}` was intended.","solutions":["Wrap the value in `RunnableLambda`: `RunnableLambda(value)` if it is a function-like object, or `RunnableLambda(lambda _: value)` for constants.","If the value is a static dict of runnables, pass the dict directly so it becomes a `RunnableParallel`.","Import the actual function/class instead of passing its name or module path as a string.","For generator-based streaming steps, pass the generator function (`def gen(x): yield ...`), not the result of calling it.","Check for None before building the chain when the value comes from an optional config or lookup."],"exampleFix":"// before\nbranch = RunnableBranch((is_q, \"answer\"), default_fn)\n\n// after\nfrom langchain_core.runnables import RunnableLambda\nbranch = RunnableBranch((is_q, RunnableLambda(lambda _: \"answer\")), default_fn)","handlingStrategy":"type-guard","validationCode":"from collections.abc import Callable, Mapping\nfrom langchain_core.runnables import Runnable\nimport inspect\n\ndef is_coercible(thing) -> bool:\n    return (\n        isinstance(thing, (Runnable, Mapping))\n        or callable(thing)\n        or inspect.isgeneratorfunction(thing)\n    )\n\nassert all(is_coercible(b) for b in branch_values), \"non-coercible branch value\"","typeGuard":"from collections.abc import Callable, Mapping\nfrom typing import TypeGuard\nimport inspect\nfrom langchain_core.runnables import Runnable\n\ndef is_runnable_coercible(thing: object) -> TypeGuard[Runnable | Callable | Mapping]:\n    return (\n        isinstance(thing, (Runnable, Mapping))\n        or callable(thing)\n        or inspect.isgeneratorfunction(thing)\n    )","tryCatchPattern":"try:\n    runnable = coerce_to_runnable(thing)\nexcept TypeError as e:\n    raise ValueError(f\"Bad chain step {thing!r}: wrap callables/consts in RunnableLambda\") from e","preventionTips":["Wrap constants in RunnableLambda(lambda _: value) at construction time.","Never pass module-path strings; import the function.","Pass generator functions, not generator objects.","Add unit tests asserting each dynamic chain step is a Runnable, callable, or dict."],"tags":["runnable","type-error","chain-composition","langchain-core"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}