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

  1. Convert the condition to a string: str(condition) or quote it in YAML.
  2. Fix Jinja2 syntax errors in the condition string (test with jinja2 Environment.from_string).
  3. If you intended function-based routing, express the logic as a Jinja expression instead of a callable.
  4. 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

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


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