{"record":{"id":"0b4682a2909d1a41","repo":"langchain-ai/langchain","slug":"recursion-limit-reached-when-invoking-self-with-0b4682","errorCode":null,"errorMessage":"Recursion limit reached when invoking {self} with input {value}.","messagePattern":"Recursion limit reached when invoking (.+?) with input (.+?)\\.","errorType":"exception","errorClass":"RecursionError","httpStatus":null,"severity":"critical","filePath":"libs/core/langchain_core/runnables/base.py","lineNumber":5278,"sourceCode":"                    if output is None:\n                        output = chunk\n                    else:\n                        try:\n                            output = output + chunk  # type: ignore[operator]\n                        except TypeError:\n                            output = chunk\n        else:\n            output = await acall_func_with_variable_args(\n                cast(\"Callable[..., Any]\", afunc), value, config, run_manager, **kwargs\n            )\n        # If the output is a Runnable, invoke it\n        if isinstance(output, Runnable):\n            recursion_limit = config[\"recursion_limit\"]\n            if recursion_limit <= 0:\n                msg = (\n                    f\"Recursion limit reached when invoking {self} with input {value}.\"\n                )\n                raise RecursionError(msg)\n            output = await output.ainvoke(\n                value,\n                patch_config(\n                    config,\n                    callbacks=run_manager.get_child(),\n                    recursion_limit=recursion_limit - 1,\n                ),\n            )\n        return cast(\"Output\", output)\n\n    @override\n    def invoke(\n        self,\n        input: Input,\n        config: RunnableConfig | None = None,\n        **kwargs: Any | None,\n    ) -> Output:\n        \"\"\"Invoke this `Runnable` synchronously.","sourceCodeStart":5260,"sourceCodeEnd":5296,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/runnables/base.py#L5260-L5296","documentation":"Async twin of the sync recursion check: in `RunnableLambda._ainvoke`, when the wrapped coroutine returns a `Runnable`, it is awaited via `output.ainvoke(...)` with `recursion_limit - 1`. At limit 0 the chain of async runnables-returning-runnables is halted with `RecursionError`. This protects async agent-style pipelines from unbounded delegation.","triggerScenarios":"An `afunc` (or async `func`) that returns a `Runnable` which again returns a `Runnable`, indefinitely; async routers where the delegate never changes the input; `config={'recursion_limit': n}` smaller than the delegation depth.","commonSituations":"Async agent loops built from `RunnableLambda` routing to the next step; deep async chains in FastAPI handlers; migrating sync recursion-limited code to async and re-hitting the limit.","solutions":["Make each delegation step strictly consume the input so recursion terminates.","Increase `recursion_limit` in the config if depth is expected: `await chain.ainvoke(x, {'recursion_limit': 100})`.","Replace recursive delegation with an explicit `while` loop or a state machine (`RunnableBranch`, LangGraph).","Log inputs per level to spot non-shrinking inputs."],"exampleFix":"# before\nasync def route(x):\n    return handler_runnable  # delegates forever on same input\n\n# after\nasync def route(x):\n    if x['done']:\n        return x\n    return await handler_runnable.ainvoke(x)  # consume and finish","handlingStrategy":"validation","validationCode":"async def ainvoke_bounded(chain, x, max_depth: int = 50):\n    return await chain.ainvoke(x, config={'recursion_limit': max_depth})","typeGuard":null,"tryCatchPattern":"try:\n    out = await chain.ainvoke(x)\nexcept RecursionError as e:\n    if 'Recursion limit reached' in str(e):\n        out = await chain.ainvoke(x, config={'recursion_limit': 100})\n    else:\n        raise","preventionTips":["Make each async delegation step transform/consume its input.","Prefer explicit loops or LangGraph state machines over recursive runnable returns.","Bound recursion_limit deliberately in async agent chains.","Log inputs per delegation level during development."],"tags":["runnable","runnable-lambda","asyncio","recursion","infinite-loop"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}