cloudflare/cloudflared · error
expect IPv4, but %s is IPv6
Error message
expect IPv4, but %s is IPv6
What it means
determineICMPv4Src resolves the local IPv4 source address used for ICMPv4 echo (ping) traffic. If the user supplied an explicit source address via configuration and that address parses as IPv6 rather than IPv4, the function returns this error. Cloudflared requires an IPv4 address to send and listen for ICMPv4 packets.
Source
Thrown at cmd/cloudflared/tunnel/configuration.go:400
if zone != "" {
logger.Info().Msgf("ICMP proxy will use %s in zone %s as source for IPv6", ipv6Src, zone)
} else {
logger.Info().Msgf("ICMP proxy will use %s as source for IPv6", ipv6Src)
}
return ipv4Src, ipv6Src, nil
}
func determineICMPv4Src(userDefinedSrc string, logger *zerolog.Logger) (netip.Addr, error) {
if userDefinedSrc != "" {
addr, err := netip.ParseAddr(userDefinedSrc)
if err != nil {
return netip.Addr{}, err
}
if addr.Is4() {
return addr, nil
}
return netip.Addr{}, fmt.Errorf("expect IPv4, but %s is IPv6", userDefinedSrc)
}
addr, err := findLocalAddr(net.ParseIP("192.168.0.1"), 53)
if err != nil {
addr = netip.IPv4Unspecified()
logger.Debug().Err(err).Msgf("Failed to determine the IPv4 for this machine. It will use %s to send/listen for ICMPv4 echo", addr)
}
return addr, nil
}
type interfaceIP struct {
name string
ip net.IP
}
func determineICMPv6Src(userDefinedSrc string, logger *zerolog.Logger, ipv4Src netip.Addr) (addr netip.Addr, zone string, err error) {
if userDefinedSrc != "" {
addr, err := netip.ParseAddr(userDefinedSrc)View on GitHub (pinned to 2253eeeb25)
Solutions
- Set the ICMPv4 source to a valid IPv4 address (e.g. 192.168.1.10)
- Remove the explicit source so cloudflared discovers one via findLocalAddr (falls back to IPv4 unspecified)
- If you intended IPv6, set the ICMPv6 source field instead
Example fix
// before $ cloudflared tunnel run --icmpv4-src ::1 // after $ cloudflared tunnel run --icmpv4-src 192.168.1.10
Defensive patterns
Strategy: validation
Validate before calling
addr, err := netip.ParseAddr(src)
if err != nil || !addr.Is4() {
return fmt.Errorf("--icmpv4-src must be an IPv4 address, got %q", src)
} Type guard
func isIPv4Literal(s string) bool { a, err := netip.ParseAddr(s); return err == nil && a.Is4() } Try / catch
if _, err := determineICMPv4Src(c); err != nil {
logger.Error().Err(err).Msg("invalid ICMPv4 source")
os.Exit(1)
} Prevention
- Omit the source flags and let cloudflared auto-discover addresses unless you have a specific requirement
- Label v4/v6 ICMP source flags clearly in deployment templates to avoid swaps
- Validate any config-rendering script output with netip.ParseAddr before shipping
When it happens
Trigger: Setting the ICMPv4 source (e.g. `--icmpv4-src` or config equivalent) to an IPv6 literal like `::1` or `2001:db8::1`, causing `addr.Is4()` to fail after parsing the user-defined address.
Common situations: Admins swap the v4 and v6 source flags by mistake; documentation examples use one field but the operator fills the other; a hostname resolves to an AAAA record where an A address was expected.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- expect IPv6, but %s is IPv4
- IPv6 bind address is specified, but edge-ip-version is IPv4
- failed to determine IPv6 source address for ICMP proxy
- funnel not found
- Invalid IP %s
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/c122c7c640ad4ad4.
Report an issue: GitHub.