{"record":{"id":"7c77bfc5408eb556","repo":"XTLS/Xray-core","slug":"failed-to-add-system-route-cidr","errorCode":null,"errorMessage":"failed to add system route {cidr}","messagePattern":"failed to add system route (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/tun/tun_linux.go","lineNumber":285,"sourceCode":"\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 {\n\tvar errs []error\n\tfor i := len(t.systemRoutes) - 1; i >= 0; i-- {\n\t\troute := t.systemRoutes[i]\n\t\tif err := netlink.RouteDel(&route); err != nil {\n\t\t\terrs = append(errs, errors.New(\"failed to delete system route\").Base(err))\n\t\t}\n\t}\n\tt.systemRoutes = nil\n\treturn errors.Combine(errs...)\n}\n","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/tun/tun_linux.go#L267-L303","documentation":"After parsing a CIDR, Xray installs a netlink route (LinkIndex = TUN, Priority 1) via netlink.RouteAdd. Failure rolls back previously added routes and returns this wrapped error. Common base causes: EEXIST (route already present with same metric), EPERM (no CAP_NET_ADMIN), ENETUNREACH (prefix not maskable/routable), or link index invalid.","triggerScenarios":"Routing table already contains the same prefix pointing at the TUN (leftover from a crashed run); running unprivileged; overlapping more-specific route that kernel merges differently; duplicates inside autoSystemRoutingTable.","commonSituations":"Restart after an unclean shutdown that left routes behind; concurrent VPN clients fighting over default routes; containers missing NET_ADMIN; duplicating 0.0.0.0/0 twice.","solutions":["Run with root/CAP_NET_ADMIN privileges","Remove stale routes before start: `ip route del <cidr> dev <tun>` or flush the table","Deduplicate overlapping CIDRs in autoSystemRoutingTable"],"exampleFix":"# before: stale route\nip route  # 0.0.0.0/1 dev tun0 metric 1 still present\n\n# after\nip route del 0.0.0.0/1 dev tun0 2>/dev/null || true\n# then start xray","handlingStrategy":"fallback","validationCode":"// pre-flight: drop stale routes that xray will install\nfor _, cidr := range cfg.AutoSystemRoutingTable {\n\t_ = exec.Command(\"ip\", \"route\", \"del\", cidr, \"dev\", tunName).Run()\n}","typeGuard":null,"tryCatchPattern":"if err := tun.Start(); err != nil {\n\tif strings.Contains(err.Error(), \"failed to add system route\") {\n\t\t// clean routes, then fall back to a single retry\n\t}\n}","preventionTips":["Ensure CAP_NET_ADMIN before starting tun mode","Clear leftover routes from crashed runs before start","Avoid running two VPN stacks managing the same prefixes"],"tags":["tun","linux","routing","netlink","permissions"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}