k3s-io/k3s · error

multiple global unicast addresses defined for %s, please set

Error message

multiple global unicast addresses defined for %s, please set ip from one of %v

What it means

After collecting global unicast IPv4 and IPv6 addresses on the interface, if more than one IPv4 global unicast exists the function refuses to guess which one to use and lists the candidates in the error. This prevents silently binding the node/cluster to the wrong IP on multi-homed hosts.

Source

Thrown at pkg/util/net.go:302

	for _, addr := range addrs {
		ip, _, err := net.ParseCIDR(addr.String())
		if err != nil {
			return "", fmt.Errorf("unable to parse CIDR for interface %s: %w", iface.Name, err)
		}
		// if not IPv4 adding it on IPv6 list
		if ip.To4() == nil {
			if ip.IsGlobalUnicast() {
				globalUnicastsIPv6 = append(globalUnicastsIPv6, ip.String())
			}
			continue
		}
		if ip.IsGlobalUnicast() {
			globalUnicasts = append(globalUnicasts, ip.String())
		}
	}

	if len(globalUnicasts) > 1 {
		return "", fmt.Errorf("multiple global unicast addresses defined for %s, please set ip from one of %v", ifaceName, globalUnicasts)
	}
	if len(globalUnicasts) == 1 && len(globalUnicastsIPv6) == 0 {
		return globalUnicasts[0], nil
	} else if len(globalUnicastsIPv6) > 0 && len(globalUnicasts) == 1 {
		return globalUnicasts[0] + "," + globalUnicastsIPv6[0], nil
	} else if len(globalUnicastsIPv6) > 0 {
		return globalUnicastsIPv6[0], nil
	}

	return "", fmt.Errorf("can't find ip for interface %s", ifaceName)
}

type multiListener struct {
	listeners []net.Listener
	closing   chan struct{}
	conns     chan acceptRes
}

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Pick one explicitly: set the node-ip (or equivalent bind-address) config to one of the candidates listed in the error
  2. Remove the extra address from that interface if it is not needed
  3. Point the interface option at a dedicated interface that has exactly one global unicast address

Example fix

# before
--flannel-iface=eth0   # eth0 holds 10.0.0.5 and 192.0.2.7
# after
--node-ip=10.0.0.5
Defensive patterns

Strategy: validation

Validate before calling

func countIPv4GlobalUnicasts(name string) ([]string, error) {
	iface, err := net.InterfaceByName(name)
	if err != nil {
		return nil, err
	}
	addrs, _ := iface.Addrs()
	found := []string{}
	for _, a := range addrs {
		if ip, _, err := net.ParseCIDR(a.String()); err == nil && ip.To4() != nil && ip.IsGlobalUnicast() {
			found = append(found, ip.String())
		}
	}
	if len(found) > 1 {
		return nil, fmt.Errorf("ambiguous: %v - set node-ip explicitly", found)
	}
	return found, nil
}

Try / catch

ip, err := util.GetIPFromInterface(cfg.Iface)
if err != nil && strings.Contains(err.Error(), "multiple global unicast addresses") {
	// candidates are listed in the error; require an explicit node-ip in config
	return "", fmt.Errorf("%w: set --node-ip explicitly", err)
}

Prevention

When it happens

Trigger: util.GetIPFromInterface on an interface with two or more public IPv4 addresses: secondary elastic IPs, floating IPs, IP aliases, or multi-homed NICs.

Common situations: Cloud nodes with extra EIPs (AWS) or floating IPs (Hetzner); load-balancer VIPs placed on the same NIC; addresses left by a CNI or metallb on the wrong interface; bare-metal hosts with multiple subnets on one interface.

Related errors


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