{"record":{"id":"7264b269219ba28d","repo":"netbirdio/netbird","slug":"delete-ip-from-ipset-w","errorCode":null,"errorMessage":"delete ip from ipset: %w","messagePattern":"delete ip from ipset: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/acl_linux.go","lineNumber":205,"sourceCode":"}\n\n// DeletePeerRule from the firewall by rule definition\nfunc (m *aclManager) DeletePeerRule(rule firewall.Rule) error {\n\tr, ok := rule.(*Rule)\n\tif !ok {\n\t\treturn fmt.Errorf(\"invalid rule type\")\n\t}\n\n\tshouldDestroyIpset := false\n\tif ipsetList, ok := m.ipsetStore.ipset(r.ipsetName); ok {\n\t\t// delete IP from ruleset IPs list and ipset\n\t\tif _, ok := ipsetList.ips[r.ip]; ok {\n\t\t\tip := net.ParseIP(r.ip)\n\t\t\tif ip == nil {\n\t\t\t\treturn fmt.Errorf(\"parse IP %s\", r.ip)\n\t\t\t}\n\t\t\tif err := m.delFromIPSet(r.ipsetName, ip); err != nil {\n\t\t\t\treturn fmt.Errorf(\"delete ip from ipset: %w\", err)\n\t\t\t}\n\t\t\tdelete(ipsetList.ips, r.ip)\n\t\t}\n\n\t\t// if after delete, set still contains other IPs,\n\t\t// no need to delete firewall rule and we should exit here\n\t\tif len(ipsetList.ips) != 0 {\n\t\t\treturn nil\n\t\t}\n\n\t\t// we delete last IP from the set, that means we need to delete\n\t\t// set itself and associated firewall rule too\n\t\tm.ipsetStore.deleteIpset(r.ipsetName)\n\t\tshouldDestroyIpset = true\n\t}\n\n\tif err := m.iptablesClient.Delete(tableName, r.chain, r.specs...); err != nil {\n\t\treturn fmt.Errorf(\"failed to delete rule: %s, %v: %w\", r.chain, r.specs, err)","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/acl_linux.go#L187-L223","documentation":"The netlink DEL of a peer IP from its ipset failed inside DeletePeerRule. The in-memory ips map guard above only proves the manager believes the element exists; the kernel set may disagree (element or whole set removed externally), which yields ErrNotExist from ipset-go. Other causes are family mismatch between the net.IP and the set, or missing CAP_NET_ADMIN.","triggerScenarios":"DeletePeerRule after an external `ipset flush`/`destroy` removed the element or set while the manager's map still lists it; agent restart that repopulated ipsetStore from state but the kernel was reset; unprivileged execution; v4 IP passed to a v6 set's delete path.","commonSituations":"Hosts where operators periodically flush ipsets; crash/restart sequences that leave the memory map ahead of the kernel; cleanup code running after the network namespace changed.","solutions":["Treat ErrNotExist as success (element already gone) and continue the delete flow, since the desired end state is achieved.","Recreate/synchronize the set when the whole set is missing before retrying the DEL.","Run with CAP_NET_ADMIN and validate the IP family against the manager's v6 flag.","Avoid external mutation of NETBIRD ipsets; use the manager's Reset to reconcile."],"exampleFix":"// before\nif err := m.delFromIPSet(r.ipsetName, ip); err != nil {\n    return fmt.Errorf(\"delete ip from ipset: %w\", err)\n}\n\n// after\nif err := m.delFromIPSet(r.ipsetName, ip); err != nil {\n    if errors.Is(err, ipset.ErrElementNotExist) || errors.Is(err, ipset.ErrSetNotExist) {\n        log.Debugf(\"ip %s already absent from ipset %s\", r.ip, r.ipsetName)\n    } else {\n        return fmt.Errorf(\"delete ip from ipset: %w\", err)\n    }\n}","handlingStrategy":"try-catch","validationCode":"// verify the element is really in the kernel set before issuing the DEL\nif err := ipset.Test(name, &ipset.Entry{IP: ip, CIDR: cidr}); err != nil {\n    if errors.Is(err, ipset.ErrElementNotExist) || errors.Is(err, ipset.ErrSetNotExist) {\n        // already gone: skip the kernel DEL, still update local maps\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := mgr.DeletePeerRule(rule); err != nil {\n    if strings.Contains(err.Error(), \"delete ip from ipset\") &&\n        (errors.Is(err, ipset.ErrElementNotExist) || errors.Is(err, ipset.ErrSetNotExist)) {\n        // element/set already absent: desired state achieved, ignore\n        err = nil\n    }\n}","preventionTips":["Treat ipset 'does not exist' outcomes on delete as success; the end state is what matters.","Do not flush or destroy NETBIRD ipsets externally; if you must, run manager Reset right after.","Keep the process privileged so netlink DEL is not EPERM.","After external ipset changes, reconcile with Reset instead of incremental deletes."],"tags":["go","linux","ipset","netlink","firewall","idempotency","netbird"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}