{"record":{"id":"11a4a1d77c7051b3","repo":"cloudflare/cloudflared","slug":"expect-ipv6-but-s-is-ipv4","errorCode":null,"errorMessage":"expect IPv6, but %s is IPv4","messagePattern":"expect IPv6, but (.+?) is IPv4","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/cloudflared/tunnel/configuration.go","lineNumber":425,"sourceCode":"\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)\n\t\tif err != nil {\n\t\t\treturn netip.Addr{}, \"\", err\n\t\t}\n\t\tif addr.Is6() {\n\t\t\treturn addr, addr.Zone(), nil\n\t\t}\n\t\treturn netip.Addr{}, \"\", fmt.Errorf(\"expect IPv6, but %s is IPv4\", userDefinedSrc)\n\t}\n\n\t// Loop through all the interfaces, the preference is\n\t// 1. The interface where ipv4Src is in\n\t// 2. Interface with IPv6 address\n\t// 3. Unspecified interface\n\n\tinterfaces, err := net.Interfaces()\n\tif err != nil {\n\t\treturn netip.IPv6Unspecified(), \"\", nil\n\t}\n\n\tinterfacesWithIPv6 := make([]interfaceIP, 0)\n\tfor _, interf := range interfaces {\n\t\tinterfaceAddrs, err := interf.Addrs()\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/cmd/cloudflared/tunnel/configuration.go#L407-L443","documentation":"determineICMPv6Src resolves the local IPv6 source address (and zone) used for ICMPv6 echo traffic. When a user-supplied source address parses as IPv4 instead of IPv6, `addr.Is6()` fails and this error is returned. The address and its IPv6 zone are both required to bind ICMPv6 sockets correctly.","triggerScenarios":"Setting the ICMPv6 source (e.g. `--icmpv6-src`) to an IPv4 literal like `192.168.0.1`, so `addr.Is6()` returns false after parsing the user-defined address.","commonSituations":"Copy-paste of the ICMPv4 source into the v6 flag; stale config files written before moving to dual-stack; automation templates parameterized with an IPv4 default.","solutions":["Set the ICMPv6 source to a valid IPv6 address, including a zone if link-local (e.g. fe80::1%eth0)","Remove the explicit source so cloudflared discovers an IPv6 address automatically","If you intended IPv4, use the ICMPv4 source field instead"],"exampleFix":"// before\n$ cloudflared tunnel run --icmpv6-src 192.168.0.1\n\n// after\n$ cloudflared tunnel run --icmpv6-src fe80::1%eth0","handlingStrategy":"validation","validationCode":"addr, err := netip.ParseAddr(src)\nif err != nil || !addr.Is6() {\n    return fmt.Errorf(\"--icmpv6-src must be an IPv6 address, got %q\", src)\n}\nif addr.IsLinkLocalUnicast() && addr.Zone() == \"\" {\n    return fmt.Errorf(\"link-local IPv6 source %q requires a zone, e.g. %q\", src, src+\"%eth0\")\n}","typeGuard":"func isIPv6Literal(s string) bool { a, err := netip.ParseAddr(s); return err == nil && a.Is6() }","tryCatchPattern":"if _, _, err := determineICMPv6Src(c); err != nil {\n    logger.Error().Err(err).Msg(\"invalid ICMPv6 source\")\n    os.Exit(1)\n}","preventionTips":["Omit the ICMPv6 source flag when possible; auto-discovery picks a working address and zone","Always include a zone for link-local addresses in configs","Differentiate v4/v6 template variables explicitly in provisioning scripts"],"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-14T00:17:10.932Z"}