{"record":{"id":"698400ba63032e05","repo":"XTLS/Xray-core","slug":"invalid-system-route-cidr","errorCode":null,"errorMessage":"invalid system route {cidr}","messagePattern":"invalid system route (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/tun/tun_linux.go","lineNumber":274,"sourceCode":"\tfor i := len(t.interfaceAddresses) - 1; i >= 0; i-- {\n\t\taddress := t.interfaceAddresses[i]\n\t\tif err := netlink.AddrDel(t.tunLink, &address); err != nil {\n\t\t\terrs = append(errs, errors.New(\"failed to delete interface address \", address.String()).Base(err))\n\t\t}\n\t}\n\tt.interfaceAddresses = nil\n\treturn errors.Combine(errs...)\n}\n\nfunc (t *LinuxTun) setSystemRoutes() error {\n\tif len(t.options.AutoSystemRoutingTable) == 0 {\n\t\treturn nil\n\t}\n\ttunIndex := t.tunLink.Attrs().Index\n\tfor _, cidr := range t.options.AutoSystemRoutingTable {\n\t\tprefix, err := netip.ParsePrefix(cidr)\n\t\tif err != nil {\n\t\t\treturn errors.New(\"invalid system route \", cidr).Base(err)\n\t\t}\n\t\tprefix = prefix.Masked()\n\t\t_, ipNet, _ := net.ParseCIDR(prefix.String())\n\t\troute := netlink.Route{\n\t\t\tLinkIndex: tunIndex,\n\t\t\tDst:       ipNet,\n\t\t\tPriority:  1,\n\t\t}\n\t\tif err := netlink.RouteAdd(&route); err != nil {\n\t\t\t_ = t.unsetSystemRoutes()\n\t\t\treturn errors.New(\"failed to add system route \", cidr).Base(err)\n\t\t}\n\t\tt.systemRoutes = append(t.systemRoutes, route)\n\t}\n\treturn nil\n}\n\nfunc (t *LinuxTun) unsetSystemRoutes() error {","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/tun/tun_linux.go#L256-L292","documentation":"For each entry of the tun inbound's \"autoSystemRoutingTable\" (a.k.a. included routes), Xray parses the string with netip.ParsePrefix and rejects non-CIDR values. Unlike gateway addresses, these entries MUST include an explicit prefix length (e.g. \"0.0.0.0/0\"), because a bare IP does not describe a route.","triggerScenarios":"An entry like \"192.168.0.0\" without \"/24\", \"1.1.1.1/99\" (bad prefix), \"::/0\" mixed with malformed strings, or stray quotes/whitespace in the JSON/YAML list.","commonSituations":"Users writing bare IPs expecting a /32 host route; converting configs from other VPN tools that accept masks; JSON edits introducing empty strings.","solutions":["Write every route as an explicit CIDR: \"192.168.0.0/24\", \"0.0.0.0/1\", host routes as \"1.1.1.1/32\"","Remove empty or placeholder entries from the list","Validate the whole list with netip.ParsePrefix before launching Xray"],"exampleFix":"// before\n\"autoSystemRoutingTable\": [\"192.168.0.0\"]\n\n// after\n\"autoSystemRoutingTable\": [\"192.168.0.0/24\"]","handlingStrategy":"validation","validationCode":"for _, cidr := range cfg.AutoSystemRoutingTable {\n\tif _, err := netip.ParsePrefix(cidr); err != nil {\n\t\tlog.Fatalf(\"bad route %q: must be CIDR like 10.0.0.0/8\", cidr)\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include prefix length (host routes need /32 or /128)","Reject empty strings in the route list during config lint","Generate route lists programmatically instead of hand-editing"],"tags":["tun","linux","config","routing","cidr"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}