XTLS/Xray-core · error
invalid system route {cidr}
Error message
invalid system route {cidr} What it means
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.
Source
Thrown at proxy/tun/tun_linux.go:274
for i := len(t.interfaceAddresses) - 1; i >= 0; i-- {
address := t.interfaceAddresses[i]
if err := netlink.AddrDel(t.tunLink, &address); err != nil {
errs = append(errs, errors.New("failed to delete interface address ", address.String()).Base(err))
}
}
t.interfaceAddresses = nil
return errors.Combine(errs...)
}
func (t *LinuxTun) setSystemRoutes() error {
if len(t.options.AutoSystemRoutingTable) == 0 {
return nil
}
tunIndex := t.tunLink.Attrs().Index
for _, cidr := range t.options.AutoSystemRoutingTable {
prefix, err := netip.ParsePrefix(cidr)
if err != nil {
return errors.New("invalid system route ", cidr).Base(err)
}
prefix = prefix.Masked()
_, ipNet, _ := net.ParseCIDR(prefix.String())
route := netlink.Route{
LinkIndex: tunIndex,
Dst: ipNet,
Priority: 1,
}
if err := netlink.RouteAdd(&route); err != nil {
_ = t.unsetSystemRoutes()
return errors.New("failed to add system route ", cidr).Base(err)
}
t.systemRoutes = append(t.systemRoutes, route)
}
return nil
}
func (t *LinuxTun) unsetSystemRoutes() error {View on GitHub (pinned to 7d214f8b09)
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
Example fix
// before "autoSystemRoutingTable": ["192.168.0.0"] // after "autoSystemRoutingTable": ["192.168.0.0/24"]
Defensive patterns
Strategy: validation
Validate before calling
for _, cidr := range cfg.AutoSystemRoutingTable {
if _, err := netip.ParsePrefix(cidr); err != nil {
log.Fatalf("bad route %q: must be CIDR like 10.0.0.0/8", cidr)
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Users writing bare IPs expecting a /32 host route; converting configs from other VPN tools that accept masks; JSON edits introducing empty strings.
Related errors
- outbound interface cannot be the TUN interface
- invalid xray.tun.fd: file descriptor is not a TUN device
- invalid xray.tun.fd: TUN device must use IFF_NO_PI
- invalid xray.tun.fd: TUN device name {actualName} does not m
- invalid interface address {address}
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/698400ba63032e05.
Report an issue: GitHub.