netbirdio/netbird · error

add IP to ipset %s: %w

Error message

add IP to ipset %s: %w

What it means

The addToIPSet helper builds an ipset Entry with the IP, CIDR 32 (v4) or 128 (v6), and Replace:true, then ipset.Add fails at netlink level. Replace makes duplicate elements safe, so realistic failures are: the named set does not exist in the kernel, the entry's family does not match the set's family, or insufficient privileges. Wrapped by callers as 'add IP to ipset: add IP to ipset <name>: ...'.

Source

Thrown at client/firewall/iptables/acl_linux.go:573

	log.Debugf("created ipset %s with type hash:net", name)
	return nil
}

func (m *aclManager) addToIPSet(name string, ip net.IP) error {
	cidr := uint8(32)
	if ip.To4() == nil {
		cidr = 128
	}

	entry := &ipset.Entry{
		IP:      ip,
		CIDR:    cidr,
		Replace: true,
	}

	if err := ipset.Add(name, entry); err != nil {
		return fmt.Errorf("add IP to ipset %s: %w", name, err)
	}

	return nil
}

func (m *aclManager) delFromIPSet(name string, ip net.IP) error {
	cidr := uint8(32)
	if ip.To4() == nil {
		cidr = 128
	}

	entry := &ipset.Entry{
		IP:   ip,
		CIDR: cidr,
	}

	if err := ipset.Del(name, entry); err != nil {
		return fmt.Errorf("delete IP from ipset %s: %w", name, err)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Ensure the set exists immediately before Add (the manager's flush-probe pattern), recreating on ErrSetNotExist.
  2. Validate ip.To4() nil-ness against the manager's v6 flag and reject/skip mismatched families at the API boundary.
  3. Run with CAP_NET_ADMIN.
  4. Remove external ipset mutation from the host.
Defensive patterns

Strategy: try-catch

Validate before calling

// family must match before Add: v4 -> CIDR 32 set, v6 -> CIDR 128 set
isV4 := ip.To4() != nil
if isV4 == mgrIsV6 {
    return errors.New("IP family mismatch: refuse add to avoid netlink EINVAL")
}

Try / catch

if err := addPeerRule(); err != nil {
    if strings.Contains(err.Error(), "add IP to ipset") {
        if errors.Is(err, ipset.ErrSetNotExist) {
            // set vanished: recreate then retry the add once
        }
        if errors.Is(err, unix.EPERM) {
            // privilege problem: escalate to deployment fix, do not retry
        }
    }
}

Prevention

When it happens

Trigger: Calling Add after the set was destroyed externally; calling the v6 manager's add path with a v4 net.IP (To4() != nil selects CIDR 32 inside an inet6 set); unprivileged process; seccomp blocking netlink ADD ops.

Common situations: External ipset janitors; dual-stack rule application routing families to the wrong manager instance; container security profiles.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/8da7ae604418ff83. Report an issue: GitHub.