deepset-ai/haystack · error · TypeError
outputs_to_state configuration for key '{key}' must be a dic
Error message
outputs_to_state configuration for key '{key}' must be a dictionary What it means
Each value in Tool.outputs_to_state must itself be a dict describing that state key's config (optional "source" and "handler"). __post_init__ raises TypeError if any per-key configuration is not a dictionary, catching configs passed as strings, callables, or other objects.
Source
Thrown at haystack/tools/tool.py:141
# `async_function` must be a coroutine function defined with `async def`.
if self.async_function is not None and not inspect.iscoroutinefunction(self.async_function):
raise ValueError(
f"`async_function` must be a coroutine function defined with `async def`. "
f"Got '{getattr(self.async_function, '__name__', repr(self.async_function))}'."
)
# Check that the parameters define a valid JSON schema
try:
Draft202012Validator.check_schema(self.parameters)
except SchemaError as e:
raise ValueError("The provided parameters do not define a valid JSON schema") from e
# Validate outputs structure if provided
if self.outputs_to_state is not None:
for key, config in self.outputs_to_state.items():
if not isinstance(config, dict):
raise TypeError(f"outputs_to_state configuration for key '{key}' must be a dictionary")
if "source" in config and not isinstance(config["source"], str):
raise ValueError(f"outputs_to_state source for key '{key}' must be a string.")
if "handler" in config and not callable(config["handler"]):
raise ValueError(f"outputs_to_state handler for key '{key}' must be callable")
# Validate that outputs_to_state source keys exist as valid tool outputs
valid_outputs: set[str] | None = self._get_valid_outputs()
if valid_outputs is not None:
for state_key, config in self.outputs_to_state.items():
source = config.get("source")
if source is not None and source not in valid_outputs:
raise ValueError(
f"outputs_to_state: '{self.name}' maps state key '{state_key}' to unknown output '{source}'"
f"Valid outputs are: {valid_outputs}."
)
if self.outputs_to_string is not None:
if "source" in self.outputs_to_string and not isinstance(self.outputs_to_string["source"], str):View on GitHub (pinned to e318778c9b)
Solutions
- Wrap each value in a dict: outputs_to_state={"result": {"handler": my_handler}}.
- If mapping a specific output, use {"result": {"source": "output_name", "handler": fn}}.
- Update code written for older haystack Tool APIs to the nested-dict config format.
Example fix
// before
Tool(name="t", function=f, outputs_to_state={"answer": my_handler})
// after
Tool(name="t", function=f, outputs_to_state={"answer": {"handler": my_handler}}) Defensive patterns
Strategy: type-guard
Validate before calling
assert all(isinstance(v, dict) for v in outputs_to_state.values()), "each outputs_to_state value must be a dict"
Type guard
def is_valid_outputs_to_state(o: object) -> bool:
return isinstance(o, dict) and all(isinstance(v, dict) for v in o.values()) Try / catch
try:
tool = Tool(name="t", function=f, outputs_to_state=ots)
except TypeError as e:
raise ValueError(f"Bad outputs_to_state config: {e}") from e Prevention
- Always wrap per-key config in a dict, e.g. {"k": {"handler": fn}}
- Update configs written for older haystack Tool APIs that passed callables directly
- Add a construction-time unit test per tool definition
When it happens
Trigger: Tool(..., outputs_to_state={"result": some_handler}) or outputs_to_state={"result": "output_name"} — passing the handler or source directly instead of wrapping it, e.g. {"result": {"handler": fn}}.
Common situations: Older Haystack API style where outputs_to_state mapped keys directly to callables; copy-pasted config from older examples after the API changed to nested dicts.
Related errors
- outputs_to_string raw_result must be a boolean.
- outputs_to_state source for key '{key}' must be a string.
- outputs_to_state handler for key '{key}' must be callable
- outputs_to_state: '{name}' maps state key '{state_key}' to u
- outputs_to_string source must be a string.
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/19aacedf1bbcb65f.
Report an issue: GitHub.