langchain-ai/langchain · error · ValueError

One or more keys do not have a corresponding runnable

Error message

One or more keys do not have a corresponding runnable

What it means

`RunnableRouter.batch` pre-validates all inputs before dispatching: if any element of the batch carries a `key` not in the router's runnables, the whole batch is rejected with this ValueError (this check runs before per-item exception handling, so `return_exceptions=True` does not bypass it).

Source

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

        return await runnable.ainvoke(actual_input, config)

    @override
    def batch(
        self,
        inputs: list[RouterInput],
        config: RunnableConfig | list[RunnableConfig] | None = None,
        *,
        return_exceptions: bool = False,
        **kwargs: Any | None,
    ) -> list[Output]:
        if not inputs:
            return []

        keys = [input_["key"] for input_ in inputs]
        actual_inputs = [input_["input"] for input_ in inputs]
        if any(key not in self.runnables for key in keys):
            msg = "One or more keys do not have a corresponding runnable"
            raise ValueError(msg)

        def invoke(
            runnable: Runnable[Input, Output], input_: Input, config: RunnableConfig
        ) -> Output | Exception:
            if return_exceptions:
                try:
                    return runnable.invoke(input_, config, **kwargs)
                except Exception as e:
                    return e
            else:
                return runnable.invoke(input_, config, **kwargs)

        runnables = [self.runnables[key] for key in keys]
        configs = get_config_list(config, len(inputs))
        with get_executor_for_config(configs[0]) as executor:
            return cast(
                "list[Output]",
                list(executor.map(invoke, runnables, actual_inputs, configs)),

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Pre-validate keys before batching: `keys = [i['key'] for i in inputs]; bad = set(keys) - set(router.runnables)` and route bad ones to a fallback.
  2. Register a runnable for every emittable key, including a catch-all.
  3. If you need per-item isolation, batch through a wrapper that catches this ValueError per item instead of relying on `return_exceptions`.

Example fix

// before
results = router.batch(inputs)  # dies if ANY key is unregistered
// after
valid = [i for i in inputs if i['key'] in router.runnables]
fallback = [i for i in inputs if i['key'] not in router.runnables]
results = [router.invoke(i) if i in valid else default_run.invoke(i['input']) for i in inputs]
Defensive patterns

Strategy: validation

Validate before calling

valid_keys = set(router.runnables)
bad = [i for i in inputs if i['key'] not in valid_keys]
if bad:
    inputs = [
        i if i['key'] in valid_keys else {'key': 'default', 'input': i['input']}
        for i in inputs
    ]
results = router.batch(inputs)

Try / catch

try:
    results = router.batch(inputs)
except ValueError as e:
    if 'corresponding runnable' in str(e):
        results = [router.invoke(i) if i['key'] in router.runnables
                   else default_run.invoke(i['input']) for i in inputs]
    else:
        raise

Prevention

When it happens

Trigger: `RouterRunnable({'a': r}).batch([{'key': 'a', ...}, {'key': 'z', ...}])` — one bad key in any batch element fails the entire call, even with `return_exceptions=True`, because the check happens up front.

Common situations: Batch-processing user requests where a classifier occasionally emits an unregistered label, killing all N requests; enum keys vs string registry entries; a newly added branch not registered before batching traffic against it.

Related errors


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