netbirdio/netbird · error

add element to set %s: %w

Error message

add element to set %s: %w

What it means

Returned by router.createIpSet when ipset.Add fails for one of the route prefixes. addPrefixToIPSet builds an ipset.Entry{IP, CIDR, Replace:true} and calls the netlink add. The kernel rejects entries whose address family differs from the set family, entries with invalid CIDR bits, or when the set vanished mid-run.

Source

Thrown at client/firewall/iptables/router_linux.go:249

func (r *router) findSets(rule []string) []string {
	var sets []string
	for i, arg := range rule {
		if arg == "-m" && i+3 < len(rule) && rule[i+1] == "set" && rule[i+2] == matchSet {
			sets = append(sets, rule[i+3])
		}
	}
	return sets
}

func (r *router) createIpSet(setName string, sources []netip.Prefix) error {
	if err := r.createIPSet(setName); err != nil {
		return fmt.Errorf("create set %s: %w", setName, err)
	}

	for _, prefix := range sources {
		if err := r.addPrefixToIPSet(setName, prefix); err != nil {
			return fmt.Errorf("add element to set %s: %w", setName, err)
		}
	}

	return nil
}

func (r *router) deleteIpSet(setName string) error {
	if err := r.destroyIPSet(setName); err != nil {
		return fmt.Errorf("destroy set %s: %w", setName, err)
	}

	log.Debugf("Deleted unused ipset %s", setName)
	return nil
}

// AddNatRule inserts an iptables rule pair into the nat chain
func (r *router) AddNatRule(pair firewall.RouterPair) error {
	if r.legacyManagement {

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Split route groups so each rule's prefixes share one address family (per-family routing rules)
  2. Ensure only one netbird daemon manages the host; stop duplicates before retrying
  3. Check 'ipset list <name>' to see whether the set exists and with which family (header 'Family: inet/inet6')
  4. Reconnect/re-apply the network map so the refcounter recreates the set atomically (down/up)
Defensive patterns

Strategy: validation

Validate before calling

// reject mixed-family prefix lists before handing them to the router
func prefixesMatchFamily(prefixes []netip.Prefix, wantV6 bool) bool {
	for _, p := range prefixes {
		if p.Addr().Is6() != wantV6 || p.Addr().Is4In6() {
			return false
		}
	}
	return true
}

Prevention

When it happens

Trigger: AddRouteFiltering/UpdateSet iterates the route's source prefixes after creating the set. A v4 prefix added to a set created with FamilyIPV6 (or vice versa) fails immediately; so does adding to a set destroyed out-of-band (ipset destroy X) or by a concurrent agent between create and add.

Common situations: Management distributes a route group mixing IPv4 and IPv6 ranges into one rule; a second netbird instance (or manual ipset flush/destroy) races the first; host with IPv6 disabled receiving v6 routes (the -v6 suffix naming in ipsetName exists precisely to avoid cross-family collisions).

Related errors


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