{"record":{"id":"7bce5345c79dc9c6","repo":"langchain-ai/langchain","slug":"no-runnable-associated-with-key-key","errorCode":null,"errorMessage":"No runnable associated with key '{key}'","messagePattern":"No runnable associated with key '(.+?)'","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/runnables/router.py","lineNumber":114,"sourceCode":"    @classmethod\n    @override\n    def get_lc_namespace(cls) -> list[str]:\n        \"\"\"Get the namespace of the LangChain object.\n\n        Returns:\n            `[\"langchain\", \"schema\", \"runnable\"]`\n        \"\"\"\n        return [\"langchain\", \"schema\", \"runnable\"]\n\n    @override\n    def invoke(\n        self, input: RouterInput, config: RunnableConfig | None = None, **kwargs: Any\n    ) -> Output:\n        key = input[\"key\"]\n        actual_input = input[\"input\"]\n        if key not in self.runnables:\n            msg = f\"No runnable associated with key '{key}'\"\n            raise ValueError(msg)\n\n        runnable = self.runnables[key]\n        return runnable.invoke(actual_input, config)\n\n    @override\n    async def ainvoke(\n        self,\n        input: RouterInput,\n        config: RunnableConfig | None = None,\n        **kwargs: Any | None,\n    ) -> Output:\n        key = input[\"key\"]\n        actual_input = input[\"input\"]\n        if key not in self.runnables:\n            msg = f\"No runnable associated with key '{key}'\"\n            raise ValueError(msg)\n\n        runnable = self.runnables[key]","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/runnables/router.py#L96-L132","documentation":"`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.","triggerScenarios":"`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.","commonSituations":"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').","solutions":["Normalize the router function's output (`.strip().lower()`) and add a default/fallback branch for unknown keys.","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.","Log the emitted key right before returning it from the routing function to see exactly what mismatches."],"exampleFix":"// before\ndef route(x):\n    return 'summarize' if x['kind'] == 's' else 'answer'\nrouter = RouterRunnable({'summarize': s_chain, 'reply': a_chain})  # 'answer' unregistered\n// after\nbranches = {'summarize': s_chain, 'answer': a_chain}\nrouter = RouterRunnable(branches)\ndef route(x):\n    key = 'summarize' if x['kind'] == 's' else 'answer'\n    return key if key in branches else 'answer'  # fallback","handlingStrategy":"type-guard","validationCode":"key = route_fn(input_)\nif key not in router.runnables:\n    key = next(iter(router.runnables))  # or a dedicated default branch\nresult = router.invoke({'key': key, 'input': input_})","typeGuard":"def is_registered_key(router, key: object) -> bool:\n    return isinstance(key, str) and key in router.runnables","tryCatchPattern":"try:\n    out = chain.invoke(input_)\nexcept ValueError as e:\n    if 'No runnable associated with key' in str(e):\n        out = default_branch.invoke(input_)\n    else:\n        raise","preventionTips":["Share one Enum between classifier and router registry.","strip().lower() keys in the routing function before returning.","Register a catch-all branch for unknown keys."],"tags":["router","lcel","dispatch","key-mismatch"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}