From 0b109f1c127e9db3866a6897f8ff34e1bebb10df Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Wed, 3 Dec 2025 16:24:21 +0100 Subject: [PATCH 1/3] Improve error messages for non-string templates in ConditionalRouter --- .../components/routers/conditional_router.py | 18 +++++++- .../routers/test_conditional_router.py | 41 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/haystack/components/routers/conditional_router.py b/haystack/components/routers/conditional_router.py index c8125b869d..b45227860e 100644 --- a/haystack/components/routers/conditional_router.py +++ b/haystack/components/routers/conditional_router.py @@ -397,10 +397,23 @@ def _validate_routes(self, routes: list[Route]): # Validate templates if not self._validate_template(self._env, route["condition"]): - raise ValueError(f"Invalid template for condition: {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}") 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}") def _extract_variables(self, env: Environment, templates: list[str]) -> set[str]: @@ -424,6 +437,9 @@ def _validate_template(self, env: Environment, template_text: str): :param template_text: A Jinja template string. :returns: `True` if the template is valid, `False` otherwise. """ + # Check if template_text is a string before attempting to parse + if not isinstance(template_text, str): + return False try: env.parse(template_text) return True diff --git a/test/components/routers/test_conditional_router.py b/test/components/routers/test_conditional_router.py index 245e451513..fe57b6491c 100644 --- a/test/components/routers/test_conditional_router.py +++ b/test/components/routers/test_conditional_router.py @@ -39,6 +39,47 @@ def test_invalid_condition_field(self): with pytest.raises(ValueError, match="Invalid template"): ConditionalRouter(routes) + def test_invalid_output_template_non_string(self): + """ + ConditionalRouter init raises a ValueError with helpful error message when output is not a string + """ + # output is an int instead of a string template + routes = [ + { + "condition": '{{ flag == "double" }}', + "output": 2, + "output_name": "num_additional_outputs", + "output_type": int, + } + ] + with pytest.raises(ValueError) as exc_info: + ConditionalRouter(routes) + error_message = str(exc_info.value) + assert "Invalid template for output" in error_message + assert "string" in error_message + assert "Jinja2 template" in error_message + assert "2" in error_message or "2!" in error_message + + def test_invalid_output_template_non_string_list(self): + """ + ConditionalRouter init raises a ValueError with helpful error message when output in list is not a string + """ + # output list contains an int instead of a string template + routes = [ + { + "condition": '{{ flag == "double" }}', + "output": ["{{streams}}", 2], + "output_name": ["streams", "num"], + "output_type": [list[int], int], + } + ] + with pytest.raises(ValueError) as exc_info: + ConditionalRouter(routes) + error_message = str(exc_info.value) + assert "Invalid template for output" in error_message + assert "string" in error_message + assert "Jinja2 template" in error_message + def test_no_vars_in_output_route_but_with_output_name(self): """ Router can't accept a route with no variables used in the output field From 0dade7e2d5bbd30a63722f1fe9a3aaf2a4b6ad53 Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Wed, 3 Dec 2025 16:30:14 +0100 Subject: [PATCH 2/3] Add reno note --- ...ional-router-template-error-message-f633f9e786a8c7fc.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 releasenotes/notes/conditional-router-template-error-message-f633f9e786a8c7fc.yaml diff --git a/releasenotes/notes/conditional-router-template-error-message-f633f9e786a8c7fc.yaml b/releasenotes/notes/conditional-router-template-error-message-f633f9e786a8c7fc.yaml new file mode 100644 index 0000000000..8934e1c0dc --- /dev/null +++ b/releasenotes/notes/conditional-router-template-error-message-f633f9e786a8c7fc.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Improved error messages in ConditionalRouter when non-string values are provided as route outputs. + Users now receive clear guidance (e.g., "use '2' instead of 2") instead of the cryptic "Can't compile non template nodes" error. From 580d033020a976a1e3eecad6707bbba7a4fa073a Mon Sep 17 00:00:00 2001 From: Vladimir Blagojevic Date: Wed, 10 Dec 2025 10:22:58 +0100 Subject: [PATCH 3/3] Minor test fix --- test/components/routers/test_conditional_router.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/components/routers/test_conditional_router.py b/test/components/routers/test_conditional_router.py index e897887e4c..1dd26f3289 100644 --- a/test/components/routers/test_conditional_router.py +++ b/test/components/routers/test_conditional_router.py @@ -59,7 +59,7 @@ def test_invalid_output_template_non_string(self): assert "Invalid template for output" in error_message assert "string" in error_message assert "Jinja2 template" in error_message - assert "2" in error_message or "2!" in error_message + assert "2" in error_message def test_invalid_output_template_non_string_list(self): """