{"record":{"id":"820b5df40d14906b","repo":"deepset-ai/haystack","slug":"invalid-template-for-output-output-r-type-ty","errorCode":null,"errorMessage":"Invalid template for output: {output!r} (type: {type(output).__name__}). Output must be a string representing a valid Jinja2 template. For example, use {str(output)!r} instead of {output!r}.","messagePattern":"Invalid template for output: (.+?) \\(type: (.+?)\\)\\. Output must be a string representing a valid Jinja2 template\\. For example, use (.+?) instead of (.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"haystack/components/routers/conditional_router.py","lineNumber":527,"sourceCode":"\n            # Condition is always a Jinja2 template — validate it\n            if not self._validate_template(self._env, route[\"condition\"]):\n                condition_value = route[\"condition\"]\n                if not isinstance(condition_value, str):\n                    raise ValueError(\n                        f\"Invalid template for condition: {condition_value!r} (type: {type(condition_value).__name__}).\"\n                        f\"Condition must be a string representing a valid Jinja2 template. \"\n                        f\"For example, use {str(condition_value)!r} instead of {condition_value!r}.\"\n                    )\n                raise ValueError(f\"Invalid template for condition: {condition_value}\")\n\n            # Only validate output as Jinja2 template when output_passthrough is False (default)\n            output_passthrough = route.get(\"output_passthrough\", False)\n            if not output_passthrough:\n                for output in outputs:\n                    if not self._validate_template(self._env, output):\n                        if not isinstance(output, str):\n                            raise ValueError(\n                                f\"Invalid template for output: {output!r} (type: {type(output).__name__}). \"\n                                f\"Output must be a string representing a valid Jinja2 template. \"\n                                f\"For example, use {str(output)!r} instead of {output!r}.\"\n                            )\n                        raise ValueError(f\"Invalid template for output: {output}\")\n\n    @staticmethod\n    def _extract_variables(env: Environment, templates: list[str]) -> set[str]:\n        \"\"\"\n        Extracts all variables from a list of Jinja template strings.\n\n        :param env: A Jinja environment.\n        :param templates: A list of Jinja template strings.\n        :returns: A set of variable names.\n        \"\"\"\n        variables = set()\n        for template in templates:\n            assigned_variables, template_variables = _extract_template_variables_and_assignments(","sourceCodeStart":509,"sourceCodeEnd":545,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/components/routers/conditional_router.py#L509-L545","documentation":"ConditionalRouter validates each route's 'output' as a Jinja2 template string in _validate_routes (called from __init__) unless output_passthrough is set. A non-string output (or an invalid template string) raises this ValueError with the value and its type.","triggerScenarios":"Passing a non-string as route 'output', e.g. {'output': 42} or {'output': None}, while output_passthrough is False (default).","commonSituations":"Programmatic route construction where output is mistakenly a number or object; deserialized configs with wrong types.","solutions":["Make the route output a string, e.g. '{{ result }}' instead of the raw value","Use the str() representation shown in the error message","Set output_passthrough=True only if you intentionally want non-templated output"],"exampleFix":"# before\n{\"condition\": \"{{ ok }}\", \"output\": 42, \"output_name\": \"out\", \"output_type\": int}\n# after\n{\"condition\": \"{{ ok }}\", \"output\": \"{{ result }}\", \"output_name\": \"out\", \"output_type\": int}","handlingStrategy":"validation","validationCode":"outputs = [r.get(\"output\") for r in routes if not r.get(\"output_passthrough\", False)]\nassert all(isinstance(o, str) for o in outputs), \"route output must be a Jinja2 template string\"","typeGuard":"def is_valid_output(output) -> bool:\n    return isinstance(output, str)","tryCatchPattern":"try:\n    router = ConditionalRouter(routes=routes)\nexcept ValueError as e:\n    if \"Invalid template for output\" in str(e):\n        routes = [{**r, \"output\": str(r[\"output\"])} for r in routes if not r.get(\"output_passthrough\", False)] + [r for r in routes if r.get(\"output_passthrough\", False)]\n        router = ConditionalRouter(routes=routes)\n    else:\n        raise","preventionTips":["Keep route outputs as template strings even for simple values: '{{ result }}'","Sanitize config-driven outputs with str() before constructing the router","Use output_passthrough=True deliberately when output is not a template"],"tags":["python","validation","jinja2","router"],"backgroundTag":"invalid-template","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}