{"record":{"id":"dc35a5e33c8ba738","repo":"netbirdio/netbird","slug":"add-ip-to-ipset-w","errorCode":null,"errorMessage":"add IP to ipset: %w","messagePattern":"add IP to ipset: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/acl_linux.go","lineNumber":117,"sourceCode":"\t// of silently leaving the chain empty.\n\tif ipsetName != \"\" && !m.ipsetSupported {\n\t\tipsetName = \"\"\n\t}\n\tproto := protoForFamily(protocol, m.v6)\n\tspecs := filterRuleSpecs(ip, proto, sPort, dPort, action, ipsetName)\n\n\tmangleSpecs := slices.Clone(specs)\n\tmangleSpecs = append(mangleSpecs,\n\t\t\"-i\", m.wgIface.Name(),\n\t\t\"-m\", \"addrtype\", \"--dst-type\", \"LOCAL\",\n\t\t\"-j\", \"MARK\", \"--set-xmark\", fmt.Sprintf(\"%#x\", nbnet.PreroutingFwmarkRedirected),\n\t)\n\n\tspecs = append(specs, \"-j\", actionToStr(action))\n\tif ipsetName != \"\" {\n\t\tif ipList, ipsetExists := m.ipsetStore.ipset(ipsetName); ipsetExists {\n\t\t\tif err := m.addToIPSet(ipsetName, ip); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"add IP to ipset: %w\", err)\n\t\t\t}\n\t\t\t// if ruleset already exists it means we already have the firewall rule\n\t\t\t// so we need to update IPs in the ruleset and return new fw.Rule object for ACL manager.\n\t\t\tipList.addIP(ip.String())\n\t\t\treturn []firewall.Rule{&Rule{\n\t\t\t\truleID:    uuid.New().String(),\n\t\t\t\tipsetName: ipsetName,\n\t\t\t\tip:        ip.String(),\n\t\t\t\tchain:     chain,\n\t\t\t\tspecs:     specs,\n\t\t\t\tv6:        m.v6,\n\t\t\t}}, nil\n\t\t}\n\n\t\tif err := m.flushIPSet(ipsetName); err != nil {\n\t\t\tif errors.Is(err, ipset.ErrSetNotExist) {\n\t\t\t\tlog.Debugf(\"flush ipset %s before use: %v\", ipsetName, err)\n\t\t\t} else {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/acl_linux.go#L99-L135","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nif err := m.addToIPSet(ipsetName, ip); err != nil {\n    return nil, fmt.Errorf(\"add IP to ipset: %w\", err)\n}\n\n// after\nif err := m.addToIPSet(ipsetName, ip); err != nil {\n    if !errors.Is(err, ipset.ErrSetNotExist) {\n        return nil, fmt.Errorf(\"add IP to ipset: %w\", err)\n    }\n    m.ipsetStore.deleteIpset(ipsetName)\n    // fall through to the flush/create/add path below to resync with the kernel\n}","handlingStrategy":"try-catch","validationCode":"// probe kernel set existence with the manager's own flush trick\nif err := ipset.Flush(ipsetName); err != nil {\n    if errors.Is(err, ipset.ErrSetNotExist) {\n        // kernel set is gone although ipsetStore tracks it: recreate before Add\n        if err := ipset.Create(ipsetName, ipset.TypeHashNet, opts); err != nil {\n            return err\n        }\n    }\n}\nif os.Geteuid() != 0 {\n    return errors.New(\"ipset ADD requires root (CAP_NET_ADMIN)\")\n}","typeGuard":null,"tryCatchPattern":"if err := m.AddPeerFiltering(ip, proto, port, action, comment); err != nil {\n    if strings.Contains(err.Error(), \"add IP to ipset\") && errors.Is(err, ipset.ErrSetNotExist) {\n        // resync: reset the acl manager and retry once\n        if rerr := m.Reset(); rerr == nil {\n            err = m.AddPeerFiltering(ip, proto, port, action, comment)\n        }\n    }\n    if err != nil { /* surface */ }\n}","preventionTips":["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."],"tags":["go","linux","iptables","ipset","firewall","acl","netbird"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}