{"record":{"id":"89aa97073e47a9dc","repo":"apache/dubbo","slug":"illegal-route-rule-89aa97","errorCode":null,"errorMessage":"Illegal route rule!","messagePattern":"Illegal route rule!","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/MultiDestConditionRouter.java","lineNumber":75,"sourceCode":"    private Map<String, ConditionMatcher> whenCondition;\n    private List<ConditionSubSet> thenCondition;\n    private boolean force;\n    protected List<ConditionMatcherFactory> matcherFactories;\n    private boolean enabled;\n\n    public MultiDestConditionRouter(URL url, MultiDestCondition multiDestCondition, boolean force, boolean enabled) {\n        super(url);\n        this.setForce(force);\n        this.enabled = enabled;\n        matcherFactories =\n                moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();\n        this.init(multiDestCondition.getFrom(), multiDestCondition.getTo());\n    }\n\n    public void init(Map<String, String> from, List<Map<String, String>> to) {\n        try {\n            if (from == null || to == null) {\n                throw new IllegalArgumentException(\"Illegal route rule!\");\n            }\n            String whenRule = from.get(\"match\");\n            Map<String, ConditionMatcher> when =\n                    StringUtils.isBlank(whenRule) || \"true\".equals(whenRule) ? new HashMap<>() : parseRule(whenRule);\n            this.whenCondition = when;\n\n            List<ConditionSubSet> thenConditions = new ArrayList<>();\n            for (Map<String, String> toMap : to) {\n                String thenRule = toMap.get(\"match\");\n                Map<String, ConditionMatcher> then = StringUtils.isBlank(thenRule) || \"false\".equals(thenRule)\n                        ? new HashMap<>()\n                        : parseRule(thenRule);\n                // NOTE: It should be determined on the business level whether the `When condition` can be empty or not.\n\n                thenConditions.add(new ConditionSubSet(\n                        then,\n                        Integer.valueOf(\n                                toMap.getOrDefault(\"weight\", String.valueOf(DefaultRouteConditionSubSetWeight)))));","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/MultiDestConditionRouter.java#L57-L93","documentation":"Thrown by MultiDestConditionRouter.init() when either the 'from' or 'to' condition map is null. This router is built from a MultiDestCondition (multi-destination routing with weighted subsets); both a source (from) and at least one destination (to) must be supplied.","triggerScenarios":"Constructing MultiDestConditionRouter with a MultiDestCondition whose getFrom() or getTo() returns null — i.e., a multi-destination route definition missing the from-block or the to-block list.","commonSituations":"Defining a multi-destination / weighted-subset route rule (typically from mesh-style or app-level routing config) and omitting the 'from' match or the 'to' destinations; malformed YAML/JSON deserializing a missing block to null.","solutions":["Provide both a non-null 'from' map and a non-null 'to' list in the MultiDestCondition.","Validate the route definition completeness before registering the router; both source and destination(s) are mandatory.","Check the upstream config (mesh/virtual-service or app routing) serialization for missing fields."],"exampleFix":"// before: to == null -> throws\nnew MultiDestConditionRouter(url, new MultiDestCondition(fromMap, null), false, true);\n\n// after: supply non-null from and to\nList<Map<String,String>> toList = List.of(Map.of(\"match\", \"provider.region=east\", \"weight\", \"80\"));\nnew MultiDestConditionRouter(url, new MultiDestCondition(fromMap, toList), false, true);","handlingStrategy":"validation","validationCode":"// Validate MultiDestCondition before constructing the router\nif (multiDestCondition.getFrom() == null || multiDestCondition.getTo() == null) {\n    throw new IllegalArgumentException(\n        \"MultiDest route requires non-null 'from' and 'to'; got from=\"\n            + multiDestCondition.getFrom() + \", to=\" + multiDestCondition.getTo());\n}\nreturn new MultiDestConditionRouter<>(url, multiDestCondition, force, enabled);","typeGuard":null,"tryCatchPattern":"try {\n    new MultiDestConditionRouter<>(url, cond, force, enabled);\n} catch (IllegalArgumentException | IllegalStateException e) {\n    log.error(\"MultiDestConditionRouter init failed (from/to missing): \" + e.getMessage());\n    // skip this router in the chain\n}","preventionTips":["Always populate both from and to when defining a multi-destination route.","Validate the route definition (YAML/JSON) for missing blocks before registering.","Treat null from/to as a config-publish bug, not a runtime transient."],"tags":["router","condition","multi-dest","config","validation"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}