netbirdio/netbird · error
destroy set %s: %w
Error message
destroy set %s: %w
What it means
Returned by router.deleteIpSet when ipset.Destroy fails. Unlike the iptables calls (DeleteIfExists), this destroy is not existence-tolerant. The kernel refuses to destroy a set that is still referenced by an iptables rule ('Set cannot be destroyed: set is in use'), and the library errors if the set does not exist or the caller lacks CAP_NET_ADMIN.
Source
Thrown at client/firewall/iptables/router_linux.go:258
}
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 {
log.Warnf("This peer is connected to a NetBird Management service with an older version. Allowing all traffic for %s", pair.Destination)
if err := r.addLegacyRouteRule(pair); err != nil {
return fmt.Errorf("add legacy routing rule: %w", err)
}
}
if !pair.Masquerade {
return nil
}View on GitHub (pinned to 93e97f4bf1)
Solutions
- Find and delete referencing rules first: sudo iptables-save | grep 'match-set' then delete them
- Verify references: sudo ipset list <name> -t (Refs: field) or ipset list -tree
- Ensure only one agent instance runs on the host
- Re-run 'sudo netbird down' or 'netbird up --debug' after clearing stale references so teardown completes
Defensive patterns
Strategy: try-catch
Validate before calling
// confirm a set is unreferenced before expecting destroy to succeed sudo ipset list <name> -t # Refs: must be 0 sudo iptables-save | grep -- "match-set <name>"
Try / catch
err := r.deleteIpSet(name)
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
return nil // already gone; teardown converges
}
if strings.Contains(err.Error(), "in use") {
// sweep referencing iptables rules, then retry once
}
return fmt.Errorf("delete ipset %s: %w", name, err)
} Prevention
- Always delete iptables rules referencing a set before destroying it
- Run exactly one netbird instance per host
- After failures, verify teardown with 'ipset list -t' and 'iptables-save | grep match-set'
When it happens
Trigger: The ipset refcounter reaches zero via ipsetCounter.Decrement (after DeleteRouteRule / removeNatRule / removeLegacyRouteRule) and calls deleteIpSet. It fails when an iptables rule outside the manager still matches with -m set --match-set <name>, when the set was already destroyed (double teardown, crash-restart race), or on permission loss.
Common situations: Unclean shutdown left a stale iptables rule referencing the set; an admin added a manual rule using NetBird's set names; two agents tearing down concurrently; running 'netbird down' after manually flushing ipsets.
Related errors
- add IP to ipset: %w
- create set %s: %w
- add element to set %s: %w
- remove nat rule: %w
- remove inverse nat rule: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/acc2c9f8bea17a09.
Report an issue: GitHub.