fatedier/frp · error

parse route %s error: %v

Error message

parse route %s error: %v

What it means

Thrown by vnet's ParseRoutes when converting the routes config ([]string of CIDRs) to net.IPNet: net.ParseCIDR failed for one entry. Each route string must be a valid CIDR network including the prefix length; the message names the offending entry and the parse error. This runs during vnet (virtual network) controller setup on both frpc and frps.

Source

Thrown at pkg/vnet/controller.go:266

// UnregisterClientRoute Remove client route from routing table
func (c *Controller) UnregisterClientRoute(name string) {
	c.clientRouter.delRoute(name)
}

// StartServerConnReadLoop starts the read loop for a server connection
// (dynamically associates with source IPs)
func (c *Controller) StartServerConnReadLoop(ctx context.Context, conn io.ReadWriteCloser, onClose func()) {
	go c.readLoopServer(ctx, conn, onClose)
}

// ParseRoutes Convert route strings to IPNet objects
func ParseRoutes(routeStrings []string) ([]net.IPNet, error) {
	routes := make([]net.IPNet, 0, len(routeStrings))
	for _, r := range routeStrings {
		_, ipNet, err := net.ParseCIDR(r)
		if err != nil {
			return nil, fmt.Errorf("parse route %s error: %v", r, err)
		}
		routes = append(routes, *ipNet)
	}
	return routes, nil
}

// Client router (based on destination IP routing)
type clientRouter struct {
	routes map[string]*routeElement
	mu     sync.RWMutex
}

func newClientRouter() *clientRouter {
	return &clientRouter{
		routes: make(map[string]*routeElement),
	}
}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Write every entry as base/prefix CIDR: routes = ["10.0.0.0/24", "fd00::/64"]
  2. Remove empty entries (no trailing commas) and any hostnames — only literal CIDRs are accepted
  3. Verify config (frpc verify / frps verify) before starting with vnet enabled

Example fix

# before
[vnet]
enabled = true
routes = ["10.0.0.0"]

# after
[vnet]
enabled = true
routes = ["10.0.0.0/24"]
Defensive patterns

Strategy: validation

Validate before calling

func validCIDRs(routes []string) bool {
    for _, r := range routes {
        if _, _, err := net.ParseCIDR(strings.TrimSpace(r)); err != nil { return false }
    }
    return true
}

Prevention

When it happens

Trigger: vnet.enabled = true with routes like "10.0.0.0" (missing /24), "10.0.0.1/8" (host bits — ParseCIDR still accepts this, but truly malformed like "10.0/8" or "abc" fails), empty strings, or IPv6 typos. The routes array in [vnet] section of frpc.toml/frps.toml.

Common situations: Writing bare IPs instead of CIDRs in routes; trailing comma producing an empty entry; assuming a DNS name or port range is allowed in routes.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/6f9e597c1a67b06f. Report an issue: GitHub.