{"record":{"id":"3c8500cc0830523a","repo":"XTLS/Xray-core","slug":"failed-to-delete-system-route","errorCode":null,"errorMessage":"failed to delete system route","messagePattern":"failed to delete system route","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"proxy/tun/tun_linux.go","lineNumber":297,"sourceCode":"\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\nfunc (t *LinuxTun) monitorRouteChanges() {\n\trouteCh := make(chan netlink.RouteUpdate)\n\tif err := netlink.RouteSubscribe(routeCh, t.routeMonitorStop); err != nil {\n\t\terrors.LogInfoInner(context.Background(), err, \"[tun] failed to subscribe route changes\")\n\t\treturn\n\t}\n\n\tlinkCh := make(chan netlink.LinkUpdate)\n\tif err := netlink.LinkSubscribe(linkCh, t.routeMonitorStop); err != nil {\n\t\terrors.LogInfoInner(context.Background(), err, \"[tun] failed to subscribe link changes\")\n\t\treturn\n\t}","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/tun/tun_linux.go#L279-L315","documentation":"During teardown (unsetSystemRoutes), Xray deletes the system routes it installed. A failing netlink.RouteDel is collected into a combined error. Almost always benign: the route was already removed externally or vanished with the TUN link's destruction.","triggerScenarios":"Route manually deleted or replaced while Xray ran; TUN interface destroyed before Xray's cleanup; kernel auto-removed routes when the link went down.","commonSituations":"SIGKILL followed by manual cleanup, then clean stop of Xray; system shutdown ordering; another network daemon managing the same prefixes.","solutions":["Verify with `ip route` that the routes are gone; if absent, ignore the message","Let Xray own route lifecycle exclusively for the TUN device","Prefer graceful stop signals over kill -9 so cleanup sees a consistent state"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := tun.Close(); err != nil {\n\tlog.Warnf(\"route cleanup: %v (verify with `ip route`)\", err)\n}","preventionTips":["Let xray exclusively own the TUN's routes","Prefer SIGTERM over SIGKILL","After stop, verify `ip route` is clean before restarting"],"tags":["tun","linux","routing","cleanup","netlink"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}