fatedier/frp · error

invalid destination IP address [%s]

Error message

invalid destination IP address [%s]

What it means

The virtual_net visitor plugin could not parse its DestinationIP option: net.ParseIP returned nil for the configured string. DestinationIP must be a literal IPv4 or IPv6 address (host route, /32 or /128), not a CIDR, hostname, or empty string (empty is caught earlier by a dedicated error).

Source

Thrown at pkg/plugin/visitor/virtual_net.go:68

func NewVirtualNetPlugin(pluginCtx PluginContext, options v1.VisitorPluginOptions) (Plugin, error) {
	opts := options.(*v1.VirtualNetVisitorPluginOptions)

	p := &VirtualNetPlugin{
		pluginCtx: pluginCtx,
		routes:    make([]net.IPNet, 0),
	}

	p.ctx, p.cancel = context.WithCancel(pluginCtx.Ctx)

	if opts.DestinationIP == "" {
		return nil, errors.New("destinationIP is required")
	}

	// Parse DestinationIP and create a host route.
	ip := net.ParseIP(opts.DestinationIP)
	if ip == nil {
		return nil, fmt.Errorf("invalid destination IP address [%s]", opts.DestinationIP)
	}

	var mask net.IPMask
	if ip.To4() != nil {
		mask = net.CIDRMask(32, 32) // /32 for IPv4
	} else {
		mask = net.CIDRMask(128, 128) // /128 for IPv6
	}
	p.routes = append(p.routes, net.IPNet{IP: ip, Mask: mask})

	return p, nil
}

func (p *VirtualNetPlugin) Name() string {
	return v1.VisitorPluginVirtualNet
}

func (p *VirtualNetPlugin) Start() {

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Set destinationIP to a single literal IP address, e.g. 10.0.0.1 or fd00::1
  2. Remove any CIDR suffix, hostname, quotes, or surrounding whitespace
  3. One plugin instance per destination host; add more visitor entries for additional IPs

Example fix

// before (frpc.toml)
[[visitors]]
name = "vn"
type = "stty"
[visitors.plugin]
type = "virtual_net"
destinationIP = "10.0.0.0/24"

// after
destinationIP = "10.0.0.3"
Defensive patterns

Strategy: validation

Validate before calling

if net.ParseIP(cfg.DestinationIP) == nil {
    return fmt.Errorf("destinationIP must be a literal IP, got %q", cfg.DestinationIP)
}

Type guard

func isValidLiteralIP(s string) bool {
    return net.ParseIP(strings.TrimSpace(s)) != nil && !strings.Contains(s, "/")
}

Prevention

When it happens

Trigger: Creating a virtual_net visitor plugin with opts.DestinationIP that net.ParseIP rejects — e.g. "10.0.0.0/24", "myhost", "10.0.0" (malformed octets), or trailing whitespace.

Common situations: User expects CIDR support and puts a network prefix in destinationIP; hostname given instead of an IP; copy-paste artifact like quotes or spaces in the TOML value.

Related errors


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