{"record":{"id":"df895483172a6af5","repo":"deepset-ai/haystack","slug":"outputs-to-string-source-must-be-a-string","errorCode":null,"errorMessage":"outputs_to_string source must be a string.","messagePattern":"outputs_to_string source must be a string\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"haystack/tools/tool.py","lineNumber":160,"sourceCode":"                if \"source\" in config and not isinstance(config[\"source\"], str):\n                    raise ValueError(f\"outputs_to_state source for key '{key}' must be a string.\")\n                if \"handler\" in config and not callable(config[\"handler\"]):\n                    raise ValueError(f\"outputs_to_state handler for key '{key}' must be callable\")\n\n            # Validate that outputs_to_state source keys exist as valid tool outputs\n            valid_outputs: set[str] | None = self._get_valid_outputs()\n            if valid_outputs is not None:\n                for state_key, config in self.outputs_to_state.items():\n                    source = config.get(\"source\")\n                    if source is not None and source not in valid_outputs:\n                        raise ValueError(\n                            f\"outputs_to_state: '{self.name}' maps state key '{state_key}' to unknown output '{source}'\"\n                            f\"Valid outputs are: {valid_outputs}.\"\n                        )\n\n        if self.outputs_to_string is not None:\n            if \"source\" in self.outputs_to_string and not isinstance(self.outputs_to_string[\"source\"], str):\n                raise ValueError(\"outputs_to_string source must be a string.\")\n            if \"handler\" in self.outputs_to_string and not callable(self.outputs_to_string[\"handler\"]):\n                raise ValueError(\"outputs_to_string handler must be callable\")\n            if \"raw_result\" in self.outputs_to_string and not isinstance(self.outputs_to_string[\"raw_result\"], bool):\n                raise ValueError(\"outputs_to_string raw_result must be a boolean.\")\n\n            if (\n                \"source\" in self.outputs_to_string\n                or \"handler\" in self.outputs_to_string\n                or \"raw_result\" in self.outputs_to_string\n            ):\n                # Single output configuration\n                for key in self.outputs_to_string:\n                    if key not in {\"source\", \"handler\", \"raw_result\"}:\n                        raise ValueError(\n                            \"Invalid outputs_to_string config. \"\n                            \"When using 'source', 'handler' or 'raw_result' at the root level, no other keys are \"\n                            \" allowed. Use individual output configs instead.\"\n                        )","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/tools/tool.py#L142-L178","documentation":"Tool.outputs_to_string (root-level config) may include a \"source\" key that must be a string naming a tool output. __post_init__ raises ValueError if \"source\" is present but not a str.","triggerScenarios":"Tool(..., outputs_to_string={\"source\": 123}) or {\"source\": [\"a\", \"b\"]} — non-string root-level source.","commonSituations":"Attempting to serialize multiple outputs in one root config instead of using per-output configs; programmatically built configs passing wrong types.","solutions":["Set \"source\" to a single output name string, e.g. {\"source\": \"documents\"}.","For multiple outputs, move to the per-output config form: {\"documents\": {\"handler\": fn}, \"answer\": {...}}.","Omit \"source\" to apply the config to the whole tool result."],"exampleFix":"// before\noutputs_to_string={\"source\": [\"doc\", \"answer\"]}\n\n// after\noutputs_to_string={\"doc\": {}, \"answer\": {\"handler\": to_text}}","handlingStrategy":"type-guard","validationCode":"ots = outputs_to_string or {}\nif \"source\" in ots and not isinstance(ots[\"source\"], str):\n    raise TypeError(\"outputs_to_string source must be a string\")","typeGuard":"def valid_root_source(ots: dict | None) -> bool:\n    return ots is None or isinstance(ots.get(\"source\", \"\"), str)","tryCatchPattern":"try:\n    tool = Tool(name=\"t\", function=f, outputs_to_string=ots)\nexcept ValueError as e:\n    if \"source must be a string\" in str(e):\n        logger.error(f\"Fix outputs_to_string: {e}\")\n    raise","preventionTips":["Use a single output-name string for root-level source","Switch to per-output configs for multiple outputs","Type-check config dicts loaded from external files"],"tags":["python","tool","config","validation"],"backgroundTag":"invalid-config-shape","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}