langchain-ai/langchain · error · ValueError
If 'exception_key' is specified then input must be a diction
Error message
If 'exception_key' is specified then input must be a dictionary.However found a type of {type(input)} for input What it means
`RunnableWithFallbacks.invoke` requires that when `exception_key` is set (failures are recorded into the input dict under that key), the input must be a `dict`, because the mechanism writes the error back into the input before running fallbacks. A non-dict input fails the `isinstance(input, dict)` check and `ValueError` is raised before any runnable executes.
Source
Thrown at libs/core/langchain_core/runnables/fallbacks.py:173
def runnables(self) -> Iterator[Runnable[Input, Output]]:
"""Iterator over the `Runnable` and its fallbacks.
Yields:
The `Runnable` then its fallbacks.
"""
yield self.runnable
yield from self.fallbacks
@override
def invoke(
self, input: Input, config: RunnableConfig | None = None, **kwargs: Any
) -> Output:
if self.exception_key is not None and not isinstance(input, dict):
msg = (
"If 'exception_key' is specified then input must be a dictionary."
f"However found a type of {type(input)} for input"
)
raise ValueError(msg)
# setup callbacks
config = ensure_config(config)
callback_manager = get_callback_manager_for_config(config)
# start the root run
run_manager = callback_manager.on_chain_start(
None,
input,
name=config.get("run_name") or self.get_name(),
run_id=config.pop("run_id", None),
)
first_error = None
last_error = None
for runnable in self.runnables:
try:
if self.exception_key and last_error is not None:
input[self.exception_key] = last_error # type: ignore[index]
child_config = patch_config(config, callbacks=run_manager.get_child())
with set_config_context(child_config) as context:View on GitHub (pinned to e32fa9a52e)
Solutions
- Remove `exception_key` if you do not need error details recorded in the input.
- Feed a dict: wrap the value as `{"input": value}` (or a meaningful key) before it reaches the fallback runnable, and update downstream prompts to read that key.
- If the input is a Pydantic object, pass `model.model_dump()`.
Example fix
# before
fb = parser.with_fallbacks([other_parser], exception_key="errors")
out = fb.invoke("some text") # ValueError
# after
out = fb.invoke({"text": "some text", "errors": None}) # and read input["text"] inside Defensive patterns
Strategy: validation
Validate before calling
if fb.exception_key is not None:
assert isinstance(inputs_payload, dict), "exception_key requires dict input"
fb.invoke(inputs_payload) Type guard
from typing import TypeGuard
def is_dict_input(x: object) -> TypeGuard[dict]:
return isinstance(x, dict) Prevention
- Only set exception_key when your pipeline carries dict payloads end-to-end.
- Standardize on dict inputs (e.g. {"text": ...}) before fallback-wrapped runnables.
- Convert Pydantic models with .model_dump() before invoke.
When it happens
Trigger: Creating a fallback with `runnable.with_fallbacks(fallbacks, exception_key="errors")` and then invoking it with a string, list, or object input: `with_fallbacks.invoke("hello")`, or a chain whose preceding step emits a plain string (e.g. a `RunnableLambda` returning text) piped into the fallback-wrapped step.
Common situations: Wrapping a parser or model step in fallbacks and feeding it a raw string; converting an existing `.with_fallbacks(...)` chain to record errors via `exception_key` without changing the pipeline so the input stays a dict; passing a Pydantic model object instead of its `.model_dump()`.
Related errors
- If 'exception_key' is specified then inputs must be dictiona
- RunnableBranch requires at least two branches
- RunnableBranch branches must be tuples or lists of length 2,
- length must be >= 0, but got {length}
- config must be a list of the same length as inputs, but got
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/004649adb1f97f87.
Report an issue: GitHub.