v2rayA/v2rayA · error

no suitable IPv4 address found

Error message

no suitable IPv4 address found

What it means

The IPv4 branch of GetBestLocalIP: when preferIPv6 is false and no suitable IPv4 address was found on any interface, it returns "no suitable IPv4 address found". It complements the IPv6 error and surfaces when the host genuinely lacks a usable IPv4 unicast address for binding.

Source

Thrown at service/kernel/v2ray/template_inbound.go:105

					}
				}
			} else {
				if ip.To4() != nil {
					// IPv4 address
					return ip, nil
				}
			}
		}
	}

	if bestIP != nil {
		return bestIP, nil
	}

	if preferIPv6 {
		return nil, errors.New("no suitable IPv6 address found")
	}
	return nil, errors.New("no suitable IPv4 address found")
}

// GetLinkLocalIPv6 returns a link-local IPv6 address as fallback
func GetLinkLocalIPv6() (net.IP, error) {
	interfaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}

	for _, iface := range interfaces {
		if iface.Flags&net.FlagUp == 0 {
			continue
		}

		// Skip TUN interfaces
		ifName := strings.ToLower(iface.Name)
		if strings.Contains(ifName, "tun") || strings.Contains(ifName, "tap") {
			continue

View on GitHub (pinned to 71e5442fc5)

Solutions

  1. Switch the preference to IPv6 (preferIPv6=true) if the host is IPv6-only.
  2. Bring up an interface with an IPv4 address or assign one (ip addr add / DHCP).
  3. Review the filter logic in GetBestLocalIP to confirm the existing IPv4 address isn't wrongly excluded.
  4. Provide an explicit sendThrough address in the config instead of auto-selection.

Example fix

// before
ip, err := GetBestLocalIP(false) // IPv4-only preference on IPv6-only host

// after
ip, err := GetBestLocalIP(true) // use IPv6 when no IPv4 is available
Defensive patterns

Strategy: fallback

Validate before calling

hasV4 := false
addrs, _ := net.InterfaceAddrs()
for _, a := range addrs {
    if ipn, ok := a.(*net.IPNet); ok && ipn.IP.To4() != nil && ipn.IP.IsGlobalUnicast() {
        hasV4 = true
    }
}
if !hasV4 { preferIPv6 = true }

Type guard

func hostHasIPv4() bool {
    addrs, err := net.InterfaceAddrs()
    if err != nil { return false }
    for _, a := range addrs {
        if ipn, ok := a.(*net.IPNet); ok && ipn.IP.To4() != nil && ipn.IP.IsGlobalUnicast() { return true }
    }
    return false
}

Try / catch

ip, err := GetBestLocalIP(false)
if err != nil {
    ip, err = GetBestLocalIP(true)
    if err != nil { return fmt.Errorf("no usable bind address: %w", err) }
}

Prevention

When it happens

Trigger: Calling GetBestLocalIP with preferIPv6=false on a host with no non-loopback (per filter) IPv4 address — e.g. IPv6-only environment or interfaces down.

Common situations: IPv6-only containers/VPS; all interfaces except loopback down; unusual filtering that excludes the host's IPv4 addresses; misconfigured sendThrough preference on an IPv6-only box.

Related errors


AI-assisted analysis of v2rayA/v2rayA@71e5442fc5 (2026-09-05). Data as JSON: /api/errors/07d9be0ae216b661. Report an issue: GitHub.