langchain-ai/langchain · error · ValueError

RunnableBranch requires at least two branches

Error message

RunnableBranch requires at least two branches

What it means

`RunnableBranch.__init__` in `langchain_core.runnables.branch` requires at least `_MIN_BRANCHES` (2) positional arguments: one or more `(condition, runnable)` pairs plus a final default runnable. With fewer than two arguments there is no conditional branch, so the constructor raises `ValueError` immediately.

Source

Thrown at libs/core/langchain_core/runnables/branch.py:99

            RunnableLike[Input, Output],
        ]
        | RunnableLike[Input, Output],
    ) -> None:
        """A `Runnable` that runs one of two branches based on a condition.

        Args:
            *branches: A list of `(condition, Runnable)` pairs.
                Defaults a `Runnable` to run if no condition is met.

        Raises:
            ValueError: If the number of branches is less than `2`.
            TypeError: If the default branch is not `Runnable`, `Callable` or `Mapping`.
            TypeError: If a branch is not a `tuple` or `list`.
            ValueError: If a branch is not of length `2`.
        """
        if len(branches) < _MIN_BRANCHES:
            msg = "RunnableBranch requires at least two branches"
            raise ValueError(msg)

        default = branches[-1]

        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 "

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Always supply at least one `(condition, runnable)` pair plus a trailing default: `RunnableBranch((cond, fn), default_fn)`.
  2. When building branches dynamically, guard: `if not pairs: just use the runnable directly instead of RunnableBranch`.
  3. If you only need one path, skip `RunnableBranch` and use the runnable or a simple conditional `RunnableLambda`.

Example fix

# before
branch = RunnableBranch(*(pairs_or_empty_list), default_fn)  # pairs empty -> ValueError

# after
if pairs:
    branch = RunnableBranch(*pairs, default_fn)
else:
    branch = default_fn
Defensive patterns

Strategy: validation

Validate before calling

branches = [(cond, fn), ...]
if len(branches) + 1 < 2:  # pairs + default
    raise ValueError("need at least one (condition, runnable) pair plus a default")

Type guard

from typing import TypeGuard

def has_enough_branches(pairs: list, default: object) -> TypeGuard[list]:
    return len(pairs) >= 1 and default is not None

Try / catch

try:
    branch = RunnableBranch(*pairs, default_fn)
except ValueError as e:
    if "at least two branches" in str(e):
        branch = default_fn  # degenerate case: no conditions
    else:
        raise

Prevention

When it happens

Trigger: Calling `RunnableBranch()` with no arguments, or with only a single default runnable, e.g. `RunnableBranch(default_fn)` or `RunnableBranch((cond, fn))` with nothing else — the last argument is always treated as the default, so a lone pair still leaves zero real branches.

Common situations: Dynamically building a branch list that ends up empty (`RunnableBranch(*pairs, default)` where `pairs == []`); misunderstanding the signature and assuming the default is optional; passing a single pair and expecting it to be the condition branch rather than the default.

Related errors


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/5f1f47ee90aa116c. Report an issue: GitHub.