{"record":{"id":"cacac0b04c6a91ab","repo":"deepset-ai/haystack","slug":"route-must-be-a-dictionary-got-route","errorCode":null,"errorMessage":"Route must be a dictionary, got: {route}","messagePattern":"Route must be a dictionary, got: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"haystack/components/routers/conditional_router.py","lineNumber":492,"sourceCode":"                # If this was a type-validation failure or missing passthrough variable, let it propagate\n                if isinstance(e, ValueError):\n                    raise\n                msg = f\"Error evaluating condition for route '{route}': {e}\"\n                raise RouteConditionException(msg) from e\n\n        raise NoRouteSelectedException(f\"No route fired. Routes: {self.routes}\")\n\n    def _validate_routes(self, routes: list[Route]) -> None:\n        \"\"\"\n        Validates a list of routes.\n\n        :param routes: A list of routes.\n        \"\"\"\n        for route in routes:\n            try:\n                keys = set(route.keys())\n            except AttributeError as e:\n                raise ValueError(f\"Route must be a dictionary, got: {route}\") from e\n\n            mandatory_fields = {\"condition\", \"output\", \"output_type\", \"output_name\"}\n            has_all_mandatory_fields = mandatory_fields.issubset(keys)\n            if not has_all_mandatory_fields:\n                raise ValueError(\n                    f\"Route must contain 'condition', 'output', 'output_type' and 'output_name' fields: {route}\"\n                )\n\n            # Validate outputs are consistent\n            outputs = route[\"output\"] if isinstance(route[\"output\"], list) else [route[\"output\"]]\n            output_types = route[\"output_type\"] if isinstance(route[\"output_type\"], list) else [route[\"output_type\"]]\n            output_names = route[\"output_name\"] if isinstance(route[\"output_name\"], list) else [route[\"output_name\"]]\n\n            # Check lengths match\n            if not len(outputs) == len(output_types) == len(output_names):\n                raise ValueError(f\"Route output, output_type and output_name must have same length: {route}\")\n\n            # Condition is always a Jinja2 template — validate it","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/components/routers/conditional_router.py#L474-L510","documentation":"During ConditionalRouter construction, _validate_routes found an entry in the routes list that is not a dictionary (it has no .keys()). A ValueError is raised at init time so malformed route definitions never reach runtime.","triggerScenarios":"ConditionalRouter(routes=[...]) where a list element is a string, tuple, Route-like object, or other non-dict instead of a dict/Route mapping.","commonSituations":"Hand-editing route lists in YAML/config and dropping the dict structure; passing a single route (not wrapped in a list) so the string is iterated character-by-character; loading legacy configs with a different route format.","solutions":["Ensure routes is a list of dictionaries (or Route dataclass instances, which are dict-convertible as intended).","If passing a single route, wrap it: routes=[route].","Fix config/YAML so each route is a mapping with keys condition/output/output_type/output_name."],"exampleFix":"// before\nrouter = ConditionalRouter(routes=\"{{ q }}\")\n// after\nrouter = ConditionalRouter(routes=[{...route dict...}])","handlingStrategy":"type-guard","validationCode":"assert all(isinstance(r, dict) for r in routes), \"every route must be a dict\"\nrouter = ConditionalRouter(routes=routes)","typeGuard":"def is_valid_route_list(routes) -> bool:\n    return isinstance(routes, list) and all(isinstance(r, dict) for r in routes)","tryCatchPattern":"try:\n    router = ConditionalRouter(routes=routes)\nexcept ValueError as e:\n    if str(e).startswith(\"Route must be a dictionary\"):\n        routes = [dict(r) if hasattr(r, \"keys\") else normalize(r) for r in routes]\n        router = ConditionalRouter(routes=routes)\n    else:\n        raise","preventionTips":["Always pass routes as a list of dicts; wrap a single route in a list.","Build routes via a helper function that constructs dicts with all required keys.","Construct ConditionalRouter early (at startup) so validation errors surface before runtime."],"tags":["router","validation","configuration"],"backgroundTag":"invalid-route-config","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}