langchain-ai/langchain · error · TypeError
RunnableBranch branches must be tuples or lists, not {type(b
Error message
RunnableBranch branches must be tuples or lists, not {type(branch)} What it means
Each non-final argument to `RunnableBranch.__init__` must be a `tuple` or `list` of the form `(condition, runnable)`. When an argument is any other type (a bare function, a string, a dict, None), the `isinstance(branch, (tuple, list))` check fails and a `TypeError` naming the offending type is raised.
Source
Thrown at libs/core/langchain_core/runnables/branch.py:120
if not isinstance(
default,
(Runnable, Callable, Mapping), # type: ignore[arg-type]
):
msg = "RunnableBranch default must be Runnable, callable or mapping."
raise TypeError(msg)
default_ = coerce_to_runnable(cast("Runnable[Input, Output]", default))
branches_ = []
for branch in branches[:-1]:
if not isinstance(branch, (tuple, list)):
msg = (
f"RunnableBranch branches must be "
f"tuples or lists, not {type(branch)}"
)
raise TypeError(msg)
if len(branch) != _MIN_BRANCHES:
msg = (
f"RunnableBranch branches must be "
f"tuples or lists of length 2, not {len(branch)}"
)
raise ValueError(msg)
condition, runnable = branch
condition = cast("Runnable[Input, bool]", coerce_to_runnable(condition))
runnable = coerce_to_runnable(cast("Runnable[Input, Output]", runnable))
branches_.append((condition, runnable))
super().__init__(
branches=branches_,
default=default_,
)
model_config = ConfigDict(View on GitHub (pinned to e32fa9a52e)
Solutions
- Wrap every condition branch as a 2-tuple: `RunnableBranch((is_q, answer_fn), default)`.
- When assembling branches programmatically, validate each element is a tuple/list of length 2 before constructing.
- Check for None/empty elements in generated branch lists and filter them out.
Example fix
# before branch = RunnableBranch(is_q, answer_fn, default_fn) # after branch = RunnableBranch((is_q, answer_fn), default_fn)
Defensive patterns
Strategy: validation
Validate before calling
for b in branches[:-1]:
assert isinstance(b, (tuple, list)), f"branch must be tuple/list, got {type(b)}: {b!r}" Type guard
from typing import TypeGuard
def is_branch_pair(b: object) -> TypeGuard[tuple | list]:
return isinstance(b, (tuple, list)) Prevention
- Always parenthesize condition branches: (condition, runnable).
- When building branches dynamically, validate shape before RunnableBranch(*branches).
- Filter out None entries from generated branch lists.
When it happens
Trigger: Passing unwrapped callables as condition branches: `RunnableBranch(is_q, answer_fn, default)`; passing a dict `{cond: fn}` instead of a pair; forgetting the parentheses around a pair; passing None from a failed lookup in a dynamically built branch list.
Common situations: Porting code from LCEL pipe syntax where bare functions are valid; building branches with `*branches` where one element is malformed; assuming keyword-style `{condition: runnable}` dicts are accepted like in older examples.
Related errors
- RunnableBranch default must be Runnable, callable or mapping
- Expected a Runnable, callable or dict.Instead got an unsuppo
- RunnableBranch requires at least two branches
- RunnableBranch branches must be tuples or lists of length 2,
- unsupported operand type(s) for +: "{self.__class__.__name__
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/e27a53d9baaabbc4.
Report an issue: GitHub.