deepset-ai/haystack · error · ValueError

Route '{output_name}' type doesn't match expected type

Error message

Route '{output_name}' type doesn't match expected type

What it means

validate_output_type=True is enabled and the produced output_value of the fired route does not match the route's declared output_type. Haystack raises ValueError so misconfigured route typing fails loudly instead of passing wrongly-typed data downstream.

Source

Thrown at haystack/components/routers/conditional_router.py:467

                                f"Ensure '{output}' is passed as an input to the router."
                            )
                        output_value = kwargs[output]
                    else:
                        # Standard Jinja2 template evaluation
                        t_output = self._env.from_string(output)
                        output_value = t_output.render(**kwargs)

                        # We suppress the exception in case the output is already a string, otherwise
                        # we try to evaluate it and would fail.
                        # This must be done cause the output could be different literal structures.
                        # This doesn't support any user types.
                        with contextlib.suppress(Exception):
                            if not self._unsafe:
                                output_value = ast.literal_eval(output_value)

                    # Validate output type if needed
                    if self._validate_output_type and not self._output_matches_type(output_value, output_type):
                        raise ValueError(f"Route '{output_name}' type doesn't match expected type")  # noqa: TRY301

                    result[output_name] = output_value

                return result

            except Exception as e:
                # If this was a type-validation failure or missing passthrough variable, let it propagate
                if isinstance(e, ValueError):
                    raise
                msg = f"Error evaluating condition for route '{route}': {e}"
                raise RouteConditionException(msg) from e

        raise NoRouteSelectedException(f"No route fired. Routes: {self.routes}")

    def _validate_routes(self, routes: list[Route]) -> None:
        """
        Validates a list of routes.

View on GitHub (pinned to e318778c9b)

Solutions

  1. Correct the route's output_type to match what the template/variable actually produces.
  2. Fix the output template so it renders a literal matching output_type (safe mode relies on ast.literal_eval).
  3. Set validate_output_type=False if validation is not needed.
  4. If the mismatch comes from a custom/invalid type, use a type _output_matches_type can handle.

Example fix

// before
Route(condition="query.len > 10", output="{{ query }}", output_type=int, output_name="out")
// after
Route(condition="query.len > 10", output="{{ query }}", output_type=str, output_name="out")
Defensive patterns

Strategy: validation

Validate before calling

route = {"condition": "q", "output": "{{ q }}", "output_type": str, "output_name": "out"}
rendered = ast.literal_eval(jinja_env.from_string(route["output"]).render(q="x"))
assert isinstance(rendered, route["output_type"]), "declared output_type mismatch"

Type guard

def output_matches(value, expected_type) -> bool:
    import typing
    return isinstance(value, expected_type) or typing.get_origin(expected_type) is not None and isinstance(value, typing.get_origin(expected_type))

Try / catch

try:
    result = router.run(query=q)
except ValueError as e:
    if "type doesn't match expected type" in str(e):
        result = fallback_router.run(query=q)
    else:
        raise

Prevention

When it happens

Trigger: ConditionalRouter(validate_output_type=True).run() where the fired route's rendered/evaluated output fails _output_matches_type against output_type (e.g. output is a string but output_type is int, or a Jinja-rendered output isn't literal_eval-able into the declared type).

Common situations: Jinja renders numbers as strings and literal_eval can't coerce them (in safe mode); output_type edited after changing the template; passthrough of an object whose runtime type differs from the declared one; invalid output_type annotations that make the matcher always fail.

Related errors


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