{"record":{"id":"c122c7c640ad4ad4","repo":"cloudflare/cloudflared","slug":"expect-ipv4-but-s-is-ipv6","errorCode":null,"errorMessage":"expect IPv4, but %s is IPv6","messagePattern":"expect IPv4, but (.+?) is IPv6","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/cloudflared/tunnel/configuration.go","lineNumber":400,"sourceCode":"\tif zone != \"\" {\n\t\tlogger.Info().Msgf(\"ICMP proxy will use %s in zone %s as source for IPv6\", ipv6Src, zone)\n\t} else {\n\t\tlogger.Info().Msgf(\"ICMP proxy will use %s as source for IPv6\", ipv6Src)\n\t}\n\n\treturn ipv4Src, ipv6Src, nil\n}\n\nfunc determineICMPv4Src(userDefinedSrc string, logger *zerolog.Logger) (netip.Addr, error) {\n\tif userDefinedSrc != \"\" {\n\t\taddr, err := netip.ParseAddr(userDefinedSrc)\n\t\tif err != nil {\n\t\t\treturn netip.Addr{}, err\n\t\t}\n\t\tif addr.Is4() {\n\t\t\treturn addr, nil\n\t\t}\n\t\treturn netip.Addr{}, fmt.Errorf(\"expect IPv4, but %s is IPv6\", userDefinedSrc)\n\t}\n\n\taddr, err := findLocalAddr(net.ParseIP(\"192.168.0.1\"), 53)\n\tif err != nil {\n\t\taddr = netip.IPv4Unspecified()\n\t\tlogger.Debug().Err(err).Msgf(\"Failed to determine the IPv4 for this machine. It will use %s to send/listen for ICMPv4 echo\", addr)\n\t}\n\treturn addr, nil\n}\n\ntype interfaceIP struct {\n\tname string\n\tip   net.IP\n}\n\nfunc determineICMPv6Src(userDefinedSrc string, logger *zerolog.Logger, ipv4Src netip.Addr) (addr netip.Addr, zone string, err error) {\n\tif userDefinedSrc != \"\" {\n\t\taddr, err := netip.ParseAddr(userDefinedSrc)","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/cmd/cloudflared/tunnel/configuration.go#L382-L418","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n$ cloudflared tunnel run --icmpv4-src ::1\n\n// after\n$ cloudflared tunnel run --icmpv4-src 192.168.1.10","handlingStrategy":"validation","validationCode":"addr, err := netip.ParseAddr(src)\nif err != nil || !addr.Is4() {\n    return fmt.Errorf(\"--icmpv4-src must be an IPv4 address, got %q\", src)\n}","typeGuard":"func isIPv4Literal(s string) bool { a, err := netip.ParseAddr(s); return err == nil && a.Is4() }","tryCatchPattern":"if _, err := determineICMPv4Src(c); err != nil {\n    logger.Error().Err(err).Msg(\"invalid ICMPv4 source\")\n    os.Exit(1)\n}","preventionTips":["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"],"tags":["network","ipv6","icmp","cli"],"backgroundTag":"invalid-argument-value","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}