langchain-ai/langchain · error · ValueError

No runnable associated with key '{key}'

Error message

No runnable associated with key '{key}'

What it means

`RunnableRouter.invoke` looked up `input['key']` in its map of runnables and found no entry. A router (typically built by `RunnableLambda(routing_fn).with_types(input_type=...)` or a `RouterRunnable`) dispatches to `self.runnables[key]`, so every key the routing function can return must be registered.

Source

Thrown at libs/core/langchain_core/runnables/router.py:114

    @classmethod
    @override
    def get_lc_namespace(cls) -> list[str]:
        """Get the namespace of the LangChain object.

        Returns:
            `["langchain", "schema", "runnable"]`
        """
        return ["langchain", "schema", "runnable"]

    @override
    def invoke(
        self, input: RouterInput, config: RunnableConfig | None = None, **kwargs: Any
    ) -> Output:
        key = input["key"]
        actual_input = input["input"]
        if key not in self.runnables:
            msg = f"No runnable associated with key '{key}'"
            raise ValueError(msg)

        runnable = self.runnables[key]
        return runnable.invoke(actual_input, config)

    @override
    async def ainvoke(
        self,
        input: RouterInput,
        config: RunnableConfig | None = None,
        **kwargs: Any | None,
    ) -> Output:
        key = input["key"]
        actual_input = input["input"]
        if key not in self.runnables:
            msg = f"No runnable associated with key '{key}'"
            raise ValueError(msg)

        runnable = self.runnables[key]

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Normalize the router function's output (`.strip().lower()`) and add a default/fallback branch for unknown keys.
  2. Make the registry and the router function share a single source of truth (e.g. an Enum or dict of names) so a new key cannot be produced without a runnable.
  3. Log the emitted key right before returning it from the routing function to see exactly what mismatches.

Example fix

// before
def route(x):
    return 'summarize' if x['kind'] == 's' else 'answer'
router = RouterRunnable({'summarize': s_chain, 'reply': a_chain})  # 'answer' unregistered
// after
branches = {'summarize': s_chain, 'answer': a_chain}
router = RouterRunnable(branches)
def route(x):
    key = 'summarize' if x['kind'] == 's' else 'answer'
    return key if key in branches else 'answer'  # fallback
Defensive patterns

Strategy: type-guard

Validate before calling

key = route_fn(input_)
if key not in router.runnables:
    key = next(iter(router.runnables))  # or a dedicated default branch
result = router.invoke({'key': key, 'input': input_})

Type guard

def is_registered_key(router, key: object) -> bool:
    return isinstance(key, str) and key in router.runnables

Try / catch

try:
    out = chain.invoke(input_)
except ValueError as e:
    if 'No runnable associated with key' in str(e):
        out = default_branch.invoke(input_)
    else:
        raise

Prevention

When it happens

Trigger: `RouterRunnable({'a': run_a, 'b': run_b}).invoke({'key': 'c', 'input': ...})` — the router function returned a key like 'c', 'default', or an enum value that was never added to the runnables dict.

Common situations: An LLM-driven routing function returns a label outside the fixed set (hallucinated or differently-cased key); adding a new branch to the router function but forgetting to register its runnable; keys registered under different casing/whitespace than produced ('Summarize' vs 'summarize').

Related errors


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