{"record":{"id":"bd0f9a72c293af1d","repo":"XTLS/Xray-core","slug":"no-valid-ip-matcher","errorCode":null,"errorMessage":"no valid ip matcher","messagePattern":"no valid ip matcher","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/geodata/ip_matcher.go","lineNumber":1013,"sourceCode":"\tif len(posGeoip) > 0 {\n\t\tipset, err := f.GetOrCreateFromGeoIPRules(posGeoip)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsubs = append(subs, &HeuristicIPMatcher{ipset: ipset, reverse: false})\n\t}\n\n\tif len(negGeoip) > 0 {\n\t\tipset, err := f.GetOrCreateFromGeoIPRules(negGeoip)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsubs = append(subs, &HeuristicIPMatcher{ipset: ipset, reverse: true})\n\t}\n\n\tswitch len(subs) {\n\tcase 0:\n\t\treturn nil, errors.New(\"no valid ip matcher\")\n\tcase 1:\n\t\treturn subs[0], nil\n\tdefault:\n\t\treturn &HeuristicMultiIPMatcher{matchers: subs}, nil\n\t}\n}\n\nfunc newIPSetFactory() *IPSetFactory {\n\treturn &IPSetFactory{shared: utils.NewWeakCacheMap[string, IPSet]()}\n}\n","sourceCodeStart":995,"sourceCodeEnd":1024,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/common/geodata/ip_matcher.go#L995-L1024","documentation":"Returned when building the heuristic IP matcher ends up with zero sub-matchers: the caller passed an empty (or fully-negated-away) list of IP rules. The switch on len(subs) hits case 0, meaning neither positive nor negative GeoIP rule lists produced any matcher.","triggerScenarios":"Constructing a router IP matcher from an empty []string of IP rules; passing only whitespace/malformed entries that were filtered out upstream; calling the builder programmatically with nil rules slice.","commonSituations":"JSON config where the routing rule's \"ip\" array is empty ([]), which Xray's JSON parser may pass through; programmatic API users building a Rule with no IP conditions and then forcing IP-matcher construction.","solutions":["Populate the rule's ip field with at least one valid entry (e.g. \"geoip:private\") or remove the empty ip array from the routing rule.","If writing Go code against the API, check len(rules) > 0 before calling the matcher constructor and return nil matcher instead.","Lint your config with `xray run -test` to catch empty arrays before runtime."],"exampleFix":"// before\n{ \"type\": \"field\", \"ip\": [], \"outboundTag\": \"block\" }\n\n// after\n{ \"type\": \"field\", \"ip\": [\"geoip:private\"], \"outboundTag\": \"block\" }","handlingStrategy":"validation","validationCode":"if len(ipRules) == 0 {\n    return nil, errors.New(\"refusing to build IP matcher: no rules supplied\")\n}","typeGuard":null,"tryCatchPattern":"if m, err := newHeuristicIPMatcher(rules, negRules); err != nil {\n    if strings.Contains(err.Error(), \"no valid ip matcher\") { /* skip IP matching for this rule */ }\n}","preventionTips":["Never emit an empty \"ip\": [] array in routing rules — omit the key instead.","Add a config lint step rejecting empty arrays for matcher fields."],"tags":["geodata","routing","config","xray"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}