deepset-ai/haystack · error · ValueError
Invalid template for condition: {condition_value!r} (type: {
Error message
Invalid template for condition: {condition_value!r} (type: {type(condition_value).__name__}).Condition must be a string representing a valid Jinja2 template. For example, use {str(condition_value)!r} instead of {condition_value!r}. What it means
The route's condition failed Jinja template validation. If the condition is not even a string, this detailed ValueError names the actual type and hints that a string was expected; a string condition with invalid Jinja syntax gets the simpler message variant. This surfaces at ConditionalRouter construction via _validate_routes.
Source
Thrown at haystack/components/routers/conditional_router.py:514
if not has_all_mandatory_fields:
raise ValueError(
f"Route must contain 'condition', 'output', 'output_type' and 'output_name' fields: {route}"
)
# Validate outputs are consistent
outputs = route["output"] if isinstance(route["output"], list) else [route["output"]]
output_types = route["output_type"] if isinstance(route["output_type"], list) else [route["output_type"]]
output_names = route["output_name"] if isinstance(route["output_name"], list) else [route["output_name"]]
# Check lengths match
if not len(outputs) == len(output_types) == len(output_names):
raise ValueError(f"Route output, output_type and output_name must have same length: {route}")
# Condition is always a Jinja2 template — validate it
if not self._validate_template(self._env, route["condition"]):
condition_value = route["condition"]
if not isinstance(condition_value, str):
raise ValueError(
f"Invalid template for condition: {condition_value!r} (type: {type(condition_value).__name__})."
f"Condition must be a string representing a valid Jinja2 template. "
f"For example, use {str(condition_value)!r} instead of {condition_value!r}."
)
raise ValueError(f"Invalid template for condition: {condition_value}")
# Only validate output as Jinja2 template when output_passthrough is False (default)
output_passthrough = route.get("output_passthrough", False)
if not output_passthrough:
for output in outputs:
if not self._validate_template(self._env, output):
if not isinstance(output, str):
raise ValueError(
f"Invalid template for output: {output!r} (type: {type(output).__name__}). "
f"Output must be a string representing a valid Jinja2 template. "
f"For example, use {str(output)!r} instead of {output!r}."
)
raise ValueError(f"Invalid template for output: {output}")View on GitHub (pinned to e318778c9b)
Solutions
- Convert the condition to a string: str(condition) or quote it in YAML.
- Fix Jinja2 syntax errors in the condition string (test with jinja2 Environment.from_string).
- If you intended function-based routing, express the logic as a Jinja expression instead of a callable.
- Validate all conditions with the router's environment before constructing it.
Example fix
// before
{"condition": lambda q: q == "a", ...}
// after
{"condition": "query == 'a'", ...} Defensive patterns
Strategy: validation
Validate before calling
import jinja2
env = jinja2.Environment()
for r in routes:
assert isinstance(r["condition"], str), f"condition must be str, got {type(r['condition']).__name__}"
env.parse(r["condition"]) # raises TemplateSyntaxError on bad Jinja Type guard
def is_valid_condition(value) -> bool:
import jinja2
if not isinstance(value, str):
return False
try:
jinja2.Environment().parse(value)
return True
except jinja2.TemplateSyntaxError:
return False Try / catch
try:
router = ConditionalRouter(routes=routes)
except ValueError as e:
if str(e).startswith("Invalid template for condition"):
routes = [{**r, "condition": str(r["condition"])} if not isinstance(r["condition"], str) else r
for r in routes]
router = ConditionalRouter(routes=routes)
else:
raise Prevention
- Keep conditions as Jinja string expressions; never pass callables or raw Python objects.
- Quote condition strings in YAML to avoid type coercion (e.g. 'on' becoming bool True).
- Pre-parse conditions with jinja2 in tests before constructing routers.
When it happens
Trigger: Passing a non-string condition (e.g. a lambda, bool, or int) in a route dict, or a string condition that fails _validate_template (invalid Jinja2 syntax) when constructing ConditionalRouter.
Common situations: Confusing route conditions with callable predicates (from other router APIs); accidental dict/int in YAML for the condition field; Jinja syntax errors like unbalanced {% %} or a stray filter pipe in condition strings.
Related errors
- Route '{output_name}' type doesn't match expected type
- Error evaluating condition for route '{route}': {e}
- No route fired. Routes: {self.routes}
- Route must be a dictionary, got: {route}
- Route must contain 'condition', 'output', 'output_type' and
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/45940184ef591be4.
Report an issue: GitHub.