k3s-io/k3s · error

tailscale does not provide an ipv4 address

Error message

tailscale does not provide an ipv4 address

What it means

The mirror of the IPv6 case: when the node runs dual-stack or IPv4-only and the tailscale/VPN integration is active, k3s overwrites the advertise address with the VPN's IPv4 address. If the VPN reports no IPv4 address, startup fails instead of advertising an unreachable address.

Source

Thrown at pkg/cli/server/server.go:539

			if vpnInfo.IPv6Address != nil {
				logrus.Infof("Changed advertise-address to %v due to VPN", vpnInfo.IPv6Address)
				if serverConfig.ControlConfig.AdvertiseIP != "" {
					logrus.Warn("Conflict in the config detected. VPN integration overwrites advertise-address but the config is setting the advertise-address parameter")
				}
				serverConfig.ControlConfig.AdvertiseIP = vpnInfo.IPv6Address.String()
			} else {
				return errors.New("tailscale does not provide an ipv6 address")
			}
		} else {
			// We are in dual-stack or ipv4-only mode
			if vpnInfo.IPv4Address != nil {
				logrus.Infof("Changed advertise-address to %v due to VPN", vpnInfo.IPv4Address)
				if serverConfig.ControlConfig.AdvertiseIP != "" {
					logrus.Warn("Conflict in the config detected. VPN integration overwrites advertise-address but the config is setting the advertise-address parameter")
				}
				serverConfig.ControlConfig.AdvertiseIP = vpnInfo.IPv4Address.String()
			} else {
				return errors.New("tailscale does not provide an ipv4 address")
			}
		}
		logrus.Warn("Etcd IP (PrivateIP) remains the local IP. Running etcd traffic over VPN is not recommended due to performance issues")
	} else {
		// if not set, try setting advertise-ip from agent node-external-ip
		if serverConfig.ControlConfig.AdvertiseIP == "" && len(cmds.AgentConfig.NodeExternalIP.Value()) != 0 {
			serverConfig.ControlConfig.AdvertiseIP = util.GetFirstValidIPString(cmds.AgentConfig.NodeExternalIP.Value())
		}

		// if not set, try setting advertise-ip from agent node-ip
		if serverConfig.ControlConfig.AdvertiseIP == "" && len(cmds.AgentConfig.NodeIP.Value()) != 0 {
			serverConfig.ControlConfig.AdvertiseIP = util.GetFirstValidIPString(cmds.AgentConfig.NodeIP.Value())
		}
	}

	// if we ended up with any advertise-ips, ensure they're added to the SAN list
	// before PrepareServer generates the apiserver serving certificate;
	// note that kube-apiserver does not support dual-stack advertise-ip as of 1.21.0:

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Make the tailnet provide the node an IPv4 address (or fix the tailscale config) and retry
  2. Move the node to IPv6-only node-ip so the IPv6 branch applies
  3. Drop --vpn-config/--vpn-auth and configure --advertise-address manually

Example fix

# before
k3s server --node-ip=10.0.0.10 --vpn-config=hostname=tsw1   # tailnet is v6-only

# after
k3s server --node-ip=fd00::10 --vpn-config=hostname=tsw1
Defensive patterns

Strategy: validation

Validate before calling

// before enabling vpn integration on ipv4/dual-stack nodes
info, _ := vpn.GetInfoFromExecutor()
if info != nil && info.IPv4Address == nil && !utilsnet.IsIPv6(net.ParseIP(cmds.AgentConfig.NodeIP.Value()[0])) {
    return errors.New("VPN has no IPv4 address; fix tailscale or drop --vpn-* flags")
}

Type guard

func vpnHasIPv4(vpnInfo *vpn.Info) bool { return vpnInfo != nil && vpnInfo.IPv4Address != nil }

Prevention

When it happens

Trigger: Node with IPv4/dual-stack node-ip started with --vpn-config/--vpn-auth where vpnInfo.IPv4Address is nil — e.g. an IPv6-only tailnet or tailscale returning only v6 addresses.

Common situations: IPv6-only tailnets where tailscale has no A record for the node; VPN executor returning incomplete info; mixing IPv6-only tailscale deployment with IPv4 k3s nodes.

Related errors


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/96cdbcabf4bb7d4e. Report an issue: GitHub.