netbirdio/netbird · error
add IP to ipset: %w
Error message
add IP to ipset: %w
What it means
Returned from the ACL manager's AddPeerFiltering fast path: the ipset name is already tracked in the in-memory ipsetStore, but the netlink ADD of the peer IP to that kernel set failed (ipset-go's ipset.Add with Replace:true). It wraps netlink errno failures such as the set no longer existing in the kernel, an address-family mismatch (IPv4 entry into an inet6 set), or missing CAP_NET_ADMIN. Because the memory store says the set exists while the kernel disagrees, it almost always indicates store/kernel desynchronization or a privilege problem rather than a bad IP.
Source
Thrown at client/firewall/iptables/acl_linux.go:117
// of silently leaving the chain empty.
if ipsetName != "" && !m.ipsetSupported {
ipsetName = ""
}
proto := protoForFamily(protocol, m.v6)
specs := filterRuleSpecs(ip, proto, sPort, dPort, action, ipsetName)
mangleSpecs := slices.Clone(specs)
mangleSpecs = append(mangleSpecs,
"-i", m.wgIface.Name(),
"-m", "addrtype", "--dst-type", "LOCAL",
"-j", "MARK", "--set-xmark", fmt.Sprintf("%#x", nbnet.PreroutingFwmarkRedirected),
)
specs = append(specs, "-j", actionToStr(action))
if ipsetName != "" {
if ipList, ipsetExists := m.ipsetStore.ipset(ipsetName); ipsetExists {
if err := m.addToIPSet(ipsetName, ip); err != nil {
return nil, fmt.Errorf("add IP to ipset: %w", err)
}
// if ruleset already exists it means we already have the firewall rule
// so we need to update IPs in the ruleset and return new fw.Rule object for ACL manager.
ipList.addIP(ip.String())
return []firewall.Rule{&Rule{
ruleID: uuid.New().String(),
ipsetName: ipsetName,
ip: ip.String(),
chain: chain,
specs: specs,
v6: m.v6,
}}, nil
}
if err := m.flushIPSet(ipsetName); err != nil {
if errors.Is(err, ipset.ErrSetNotExist) {
log.Debugf("flush ipset %s before use: %v", ipsetName, err)
} else {View on GitHub (pinned to 93e97f4bf1)
Solutions
- Run the agent as root (or grant CAP_NET_ADMIN and CAP_NET_MODULE) so netlink ADD succeeds.
- On ipset.ErrSetNotExist, self-heal: drop the stale entry from ipsetStore and fall through to the flush/create path instead of returning the error.
- Verify family alignment: v6 managers must only receive v6 peer IPs, v4 managers only v4.
- Stop concurrent external mutation of the NETBIRD ipsets, or call aclManager.Reset() after such mutation to resynchronize.
Example fix
// before
if err := m.addToIPSet(ipsetName, ip); err != nil {
return nil, fmt.Errorf("add IP to ipset: %w", err)
}
// after
if err := m.addToIPSet(ipsetName, ip); err != nil {
if !errors.Is(err, ipset.ErrSetNotExist) {
return nil, fmt.Errorf("add IP to ipset: %w", err)
}
m.ipsetStore.deleteIpset(ipsetName)
// fall through to the flush/create/add path below to resync with the kernel
} Defensive patterns
Strategy: try-catch
Validate before calling
// probe kernel set existence with the manager's own flush trick
if err := ipset.Flush(ipsetName); err != nil {
if errors.Is(err, ipset.ErrSetNotExist) {
// kernel set is gone although ipsetStore tracks it: recreate before Add
if err := ipset.Create(ipsetName, ipset.TypeHashNet, opts); err != nil {
return err
}
}
}
if os.Geteuid() != 0 {
return errors.New("ipset ADD requires root (CAP_NET_ADMIN)")
} Try / catch
if err := m.AddPeerFiltering(ip, proto, port, action, comment); err != nil {
if strings.Contains(err.Error(), "add IP to ipset") && errors.Is(err, ipset.ErrSetNotExist) {
// resync: reset the acl manager and retry once
if rerr := m.Reset(); rerr == nil {
err = m.AddPeerFiltering(ip, proto, port, action, comment)
}
}
if err != nil { /* surface */ }
} Prevention
- Run the agent as root or with CAP_NET_ADMIN/CAP_NET_MODULE.
- Never manipulate NETBIRD ipsets with external tooling while the agent runs; use the manager's Reset to reconcile after unavoidable changes.
- Route v4 peer IPs only to the v4 manager and v6 peers only to the v6 manager so set family and entry family always match.
- After an unclean shutdown, call Reset before re-adding rules so ipsetStore and the kernel cannot disagree.
When it happens
Trigger: Calling AddPeerFiltering for a peer whose ruleset ipset is in ipsetStore while the kernel set was destroyed out-of-band (external `ipset destroy`, `ipset flush -` + reload, netns teardown); running the agent without CAP_NET_ADMIN; a v6 aclManager (m.v6 true, set created with FamilyIPV6) receiving a v4 net.IP, producing a CIDR/32 entry in an inet6 set.
Common situations: Operators or parallel firewall tooling (fail2ban, k8s NetworkManager scripts) wiping ipsets while the agent runs; containers started without NET_ADMIN; leftover manager state after an agent crash where the kernel was cleaned but ipsetStore was repopulated from persisted state; mixed-family peer addresses on dual-stack setups.
Related errors
- failed to check rule: %w
- rule already exists
- failed to delete rule: %s, %v: %w
- create ipset: %w
- delete ip from ipset: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/dc35a5e33c8ba738.
Report an issue: GitHub.