AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

RunnableParallel Ignores Max_concurrency On Ainvoke/Astream While Invoke/Stream Honour It

RunnableParallel's async execution paths (ainvoke and _atransform) do not read the `max_concurrency` configuration key, causing all branches to run concurrently and potentially violating downstream rate limits. The sync path correctly uses a thread pool with the configured limit.

highConfidence 95%LangChainAffected V1.6.5

Origin Analysis

In `langchain_core.runnables.base.RunnableParallel`, `ainvoke` and `_atransform` build coroutines for each branch and directly `await asyncio.gather(*coros)`, ignoring `config.get('max_concurrency')`. The sync path uses `get_executor_for_config(config)`, which respects `max_concurrency`.
Run the provided reproduction script with BRANCHES=4 and CAP=1. Observe that `invoke` reports peak concurrent branches = 1, while `ainvoke` reports peak = 4, exiting with code 1.

Fixing Code Block

Edge Case Audit

This change may reduce async throughput if `max_concurrency` is set lower than the number of branches, which is the intended behavior but could surprise users relying on full parallelism. It also introduces an implicit semaphore that may interact with nested runnables that already use their own concurrency limits. If network calls become serialized unexpectedly, verify that `max_concurrency` is not set globally in callbacks or chain configs. Rollback advice: revert to the previous implementation or set `max_concurrency=None` explicitly to restore unlimited async concurrency.

Ecosystem Topology