{"record":{"id":"398937e4a7c07cee","repo":"k3s-io/k3s","slug":"tailscale-does-not-provide-an-ipv6-address","errorCode":null,"errorMessage":"tailscale does not provide an ipv6 address","messagePattern":"tailscale does not provide an ipv6 address","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/cli/server/server.go","lineNumber":528,"sourceCode":"\t}\n\n\tlogrus.Info(\"Starting \" + version.Program + \" \" + app.App.Version)\n\n\tnotifySocket := os.Getenv(\"NOTIFY_SOCKET\")\n\tos.Unsetenv(\"NOTIFY_SOCKET\")\n\n\t// try setting advertise-ip from agent VPN\n\tif vpnInfo, _ := vpn.GetInfoFromExecutor(); vpnInfo != nil {\n\t\t// If we are in ipv6-only mode, we should pass the ipv6 address. Otherwise, ipv4\n\t\tif utilsnet.IsIPv6(nodeIPs[0]) {\n\t\t\tif vpnInfo.IPv6Address != nil {\n\t\t\t\tlogrus.Infof(\"Changed advertise-address to %v due to VPN\", vpnInfo.IPv6Address)\n\t\t\t\tif serverConfig.ControlConfig.AdvertiseIP != \"\" {\n\t\t\t\t\tlogrus.Warn(\"Conflict in the config detected. VPN integration overwrites advertise-address but the config is setting the advertise-address parameter\")\n\t\t\t\t}\n\t\t\t\tserverConfig.ControlConfig.AdvertiseIP = vpnInfo.IPv6Address.String()\n\t\t\t} else {\n\t\t\t\treturn errors.New(\"tailscale does not provide an ipv6 address\")\n\t\t\t}\n\t\t} else {\n\t\t\t// We are in dual-stack or ipv4-only mode\n\t\t\tif vpnInfo.IPv4Address != nil {\n\t\t\t\tlogrus.Infof(\"Changed advertise-address to %v due to VPN\", vpnInfo.IPv4Address)\n\t\t\t\tif serverConfig.ControlConfig.AdvertiseIP != \"\" {\n\t\t\t\t\tlogrus.Warn(\"Conflict in the config detected. VPN integration overwrites advertise-address but the config is setting the advertise-address parameter\")\n\t\t\t\t}\n\t\t\t\tserverConfig.ControlConfig.AdvertiseIP = vpnInfo.IPv4Address.String()\n\t\t\t} else {\n\t\t\t\treturn errors.New(\"tailscale does not provide an ipv4 address\")\n\t\t\t}\n\t\t}\n\t\tlogrus.Warn(\"Etcd IP (PrivateIP) remains the local IP. Running etcd traffic over VPN is not recommended due to performance issues\")\n\t} else {\n\t\t// if not set, try setting advertise-ip from agent node-external-ip\n\t\tif serverConfig.ControlConfig.AdvertiseIP == \"\" && len(cmds.AgentConfig.NodeExternalIP.Value()) != 0 {\n\t\t\tserverConfig.ControlConfig.AdvertiseIP = util.GetFirstValidIPString(cmds.AgentConfig.NodeExternalIP.Value())","sourceCodeStart":510,"sourceCodeEnd":546,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/cli/server/server.go#L510-L546","documentation":"With the built-in tailscale/VPN integration (--vpn-config/--vpn-auth), k3s derives the advertise address from the VPN address instead of the node IP. When the node's primary IP is IPv6-only, k3s requires the VPN to provide an IPv6 address; if tailscale reports none, startup fails rather than advertising an unreachable address.","triggerScenarios":"Node whose first node-ip is IPv6 (ipv6-only mode) started with `--vpn-config=tailscale...` where vpnInfo.IPv6Address is nil — e.g. tailscale interface only bound to IPv4.","commonSituations":"IPv6-only clusters adding tailscale for node-to-node connectivity; tailscale version that does not expose v6 addresses on the tailnet; stale VPN info returned via the vpn-info hook.","solutions":["Ensure the tailnet assigns the node an IPv6 address (tailscale side) and restart with the VPN info refreshed","Switch the node to dual-stack or IPv4 node-ip so the IPv4 path in this code is used","If VPN integration is not required, remove --vpn-config/--vpn-auth flags and set --advertise-address explicitly"],"exampleFix":"# before (ipv6-only node, tailscale has no v6)\nk3s server --node-ip=fd00::10 --vpn-config=hostname=tsw1\n\n# after (dual-stack node uses IPv4 path)\nk3s server --node-ip=10.0.0.10,fd00::10 --vpn-config=hostname=tsw1","handlingStrategy":"validation","validationCode":"// before enabling vpn integration on an ipv6-only node\nips := cmds.AgentConfig.NodeIP.Value()\nif len(ips) > 0 && utilsnet.IsIPv6(net.ParseIP(ips[0])) {\n    info, _ := vpn.GetInfoFromExecutor()\n    if info != nil && info.IPv6Address == nil {\n        return errors.New(\"VPN has no IPv6 address; fix tailscale or drop --vpn-* flags\")\n    }\n}","typeGuard":"func vpnHasNeededFamily(vpnInfo *vpn.Info, wantIPv6 bool) bool {\n    if vpnInfo == nil {\n        return false\n    }\n    if wantIPv6 {\n        return vpnInfo.IPv6Address != nil\n    }\n    return vpnInfo.IPv4Address != nil\n}","tryCatchPattern":null,"preventionTips":["Check tailscale IPs (`tailscale ip`) match the node's IP family before starting k3s with --vpn-* flags","Avoid ipv6-only tailnets for mixed-family clusters","Note that VPN integration overwrites --advertise-address; set expectations in config reviews"],"tags":["tailscale","vpn","ipv6","networking"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}