cloudflare/cloudflared · error
IPv6 bind address is specified, but edge-ip-version is IPv4
Error message
IPv6 bind address is specified, but edge-ip-version is IPv4
What it means
adjustIPVersionByBindAddress reconciles the --edge-ip-version flag with the bind address configured for cloudflared. When the bind address is an IPv6 address (or the config resolves to IPv6-only) but edge-ip-version is set to IPv4, the function returns IPv6Only and this error because the two settings are contradictory. Cloudflared cannot connect to the edge over IPv4 while bound to an IPv6 local address.
Source
Thrown at cmd/cloudflared/tunnel/configuration.go:350
return err
}
_ = listener.Close()
return nil
}
func adjustIPVersionByBindAddress(ipVersion allregions.ConfigIPVersion, ip net.IP) (allregions.ConfigIPVersion, error) {
if ip == nil {
return ipVersion, nil
}
// https://pkg.go.dev/net#IP.To4: "If ip is not an IPv4 address, To4 returns nil."
if ip.To4() != nil {
if ipVersion == allregions.IPv6Only {
return allregions.IPv4Only, fmt.Errorf("IPv4 bind address is specified, but edge-ip-version is IPv6")
}
return allregions.IPv4Only, nil
} else {
if ipVersion == allregions.IPv4Only {
return allregions.IPv6Only, fmt.Errorf("IPv6 bind address is specified, but edge-ip-version is IPv4")
}
return allregions.IPv6Only, nil
}
}
func newICMPRouter(c *cli.Context, logger *zerolog.Logger) (ingress.ICMPRouterServer, error) {
ipv4Src, ipv6Src, err := determineICMPSources(c, logger)
if err != nil {
return nil, err
}
icmpRouter, err := ingress.NewICMPRouter(ipv4Src, ipv6Src, logger, icmpFunnelTimeout)
if err != nil {
return nil, err
}
return icmpRouter, nil
}
View on GitHub (pinned to 2253eeeb25)
Solutions
- Change --edge-ip-version to 6 (or remove it) so it matches the IPv6 bind address
- Change the bind address to an IPv4 address (e.g. 0.0.0.0) to match edge-ip-version=4
- Remove the explicit bind address so cloudflared auto-selects a source matching edge-ip-version
Example fix
// before (config.yml) edge-ip-version: 4 protocol: quic bind-address: "[::]:0" // after edge-ip-version: 6 protocol: quic bind-address: "[::]:0"
Defensive patterns
Strategy: validation
Validate before calling
ipV4, _ := netip.ParseAddr(bindAddr)
edgeIsV4 := edgeIPVersion == "4"
if ipV4.Is6() && edgeIsV4 {
return fmt.Errorf("bind address %s is IPv6 but edge-ip-version is 4", bindAddr)
} Type guard
func isIPv6Bind(addr string) bool { a, err := netip.ParseAddr(addr); return err == nil && a.Is6() } Try / catch
if err := adjustIPVersionByBindAddress(ipVersion, bindAddr); err != nil {
logger.Error().Err(err).Msg("conflicting edge-ip-version and bind-address")
return err
} Prevention
- Keep edge-ip-version and bind-address in one place in your config so they are reviewed together
- In automation, derive one setting from the other instead of hardcoding both
- Test config changes with `cloudflared tunnel ingress validate`-style dry checks before deploying
When it happens
Trigger: Running `cloudflared tunnel` with `--edge-ip-version 4` while the `--bind-address` (or equivalent config field) points at an IPv6 address such as `::` or `::1`, or while the resolved region set is IPv6Only.
Common situations: Operators copy an IPv6 bind address from a dual-stack host into a config file that also pins edge-ip-version to 4; automation scripts set edge-ip-version for IPv4-only networks but inherit a stale IPv6 bind address; Kubernetes/host networking defaults change underneath the config.
Related errors
- expect IPv4, but %s is IPv6
- expect IPv6, but %s is IPv4
- failed to determine IPv6 source address for ICMP proxy
- No configuration file was found. Please create one, or use t
- ErrNoIngressRulesCLI
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/af034991977beb05.
Report an issue: GitHub.