langchain-ai/langchain · critical · RecursionError

Recursion limit reached when invoking {self} with input {inp

Error message

Recursion limit reached when invoking {self} with input {input_}.

What it means

In `RunnableLambda._invoke`, if the wrapped function returns a `Runnable`, the lambda transparently invokes it, decrementing `config['recursion_limit']` each level. When the limit reaches 0, a `RecursionError` is raised to stop unbounded (or accidentally infinite) runnables-returning-runnables chains. This is the same mechanism that halts runaway LangGraph-style loops built purely from runnables.

Source

Thrown at libs/core/langchain_core/runnables/base.py:5178

                if output is None:
                    output = chunk
                else:
                    try:
                        output = output + chunk  # type: ignore[operator]
                    except TypeError:
                        output = chunk
        else:
            output = call_func_with_variable_args(
                self.func, input_, config, run_manager, **kwargs
            )
        # If the output is a Runnable, invoke it
        if isinstance(output, Runnable):
            recursion_limit = config["recursion_limit"]
            if recursion_limit <= 0:
                msg = (
                    f"Recursion limit reached when invoking {self} with input {input_}."
                )
                raise RecursionError(msg)
            output = output.invoke(
                input_,
                patch_config(
                    config,
                    callbacks=run_manager.get_child(),
                    recursion_limit=recursion_limit - 1,
                ),
            )
        return cast("Output", output)

    async def _ainvoke(
        self,
        value: Input,
        run_manager: AsyncCallbackManagerForChainRun,
        config: RunnableConfig,
        **kwargs: Any,
    ) -> Output:
        if hasattr(self, "afunc"):

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Break the cycle: ensure the delegated invocation consumes/transforms input so recursion terminates (e.g. return `output.invoke(x)` result, not the runnable chain itself).
  2. Raise the limit if the depth is legitimate: `runnable.invoke(x, config={'recursion_limit': 100})`.
  3. Restructure mutual delegation into an explicit loop or `RunnableSequence` instead of nested returns.
  4. Debug by printing the lambda inputs at each level to detect non-terminating delegation.

Example fix

// before
step = RunnableLambda(lambda x: x + 1)
loop = RunnableLambda(lambda x: step)  # returns a Runnable -> infinite delegation

// after
step = RunnableLambda(lambda x: x + 1)
loop = RunnableLambda(lambda x: step.invoke(x, config) if isinstance(x, int) else x)
// better: express the pipeline directly
chain = step | step | step
Defensive patterns

Strategy: validation

Validate before calling

def invoke_bounded(chain, x, max_depth: int = 50):
    return chain.invoke(x, config={'recursion_limit': max_depth})

# and ensure lambdas never re-return a Runnable for identical input:
def terminates(fn, sample) -> bool:
    out = fn(sample)
    return not isinstance(out, type(None))

Try / catch

try:
    out = chain.invoke(x)
except RecursionError as e:
    if 'Recursion limit reached' in str(e):
        out = chain.invoke(x, config={'recursion_limit': 100})  # only if depth is legitimate
    else:
        raise

Prevention

When it happens

Trigger: A lambda that returns a runnable chosen dynamically (`RunnableLambda(lambda x: route(x).invoke(...)` style self-delegation without consuming input); mutually delegating runnables; `config={'recursion_limit': 0 or small N}` with N levels of nested runnable-returning lambdas; long agent loops composed of `RunnableLambda`s.

Common situations: Building routers/agents where each lambda returns the next runnable and input never changes, creating an infinite chain; legitimately deep pipelines (dozens of nested runnable returns) hitting the default limit (25); users lowering `recursion_limit` to fail fast.

Related errors


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