deepset-ai/haystack · error · ValueError

outputs_to_state source for key '{key}' must be a string.

Error message

outputs_to_state source for key '{key}' must be a string.

What it means

When an outputs_to_state entry includes a "source" key, its value must be a string naming the tool output to read. __post_init__ raises ValueError when config["source"] is present but not a str (e.g. a list, int, or None explicitly passed).

Source

Thrown at haystack/tools/tool.py:143

        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):
                raise ValueError("outputs_to_string source must be a string.")
            if "handler" in self.outputs_to_string and not callable(self.outputs_to_string["handler"]):

View on GitHub (pinned to e318778c9b)

Solutions

  1. Set "source" to the exact string name of one tool output: {"k": {"source": "documents"}}.
  2. To map multiple outputs, create one entry per output/state key rather than a list source.
  3. Omit "source" entirely if the whole tool result should feed the state key.

Example fix

// before
outputs_to_state={"k": {"source": ["doc", "answer"]}}

// after
outputs_to_state={"docs": {"source": "doc"}, "ans": {"source": "answer"}}
Defensive patterns

Strategy: type-guard

Validate before calling

for k, cfg in outputs_to_state.items():
    if "source" in cfg and not isinstance(cfg["source"], str):
        raise TypeError(f"source for '{k}' must be a string")

Type guard

def has_valid_sources(ots: dict) -> bool:
    return all(isinstance(c.get("source", ""), str) for c in ots.values())

Try / catch

try:
    tool = Tool(name="t", function=f, outputs_to_state=ots)
except ValueError as e:
    if "source" in str(e):
        logger.error(f"Fix outputs_to_state source types: {e}")
    raise

Prevention

When it happens

Trigger: Tool(..., outputs_to_state={"k": {"source": 42}}) or {"k": {"source": ["out1", "out2"]}} — a non-string source value.

Common situations: Confusing source with the state-key mapping of multiple outputs; programmatically generated configs where the source is a list of outputs; typos yielding a non-str default value.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/fa8cec00921cbf47. Report an issue: GitHub.