netbirdio/netbird · error
remove legacy routing rule: %w
Error message
remove legacy routing rule: %w
What it means
Returned by router.RemoveNatRule when removeLegacyRouteRule fails. Note this call is unconditional: it runs even when the router is not in legacy mode, but only acts if a legacy rule key exists in r.rules (i.e. a legacy ACCEPT rule was previously installed). The inner failures are the DeleteIfExists on NETBIRD-RT-FWD-IN (error 550) or the ipset counter decrement (error 551).
Source
Thrown at client/firewall/iptables/router_linux.go:304
r.updateState()
return nil
}
// RemoveNatRule removes an iptables rule pair from forwarding and nat chains
func (r *router) RemoveNatRule(pair firewall.RouterPair) error {
if pair.Masquerade {
if err := r.removeNatRule(pair); err != nil {
return fmt.Errorf("remove nat rule: %w", err)
}
if err := r.removeNatRule(firewall.GetInversePair(pair)); err != nil {
return fmt.Errorf("remove inverse nat rule: %w", err)
}
}
if err := r.removeLegacyRouteRule(pair); err != nil {
return fmt.Errorf("remove legacy routing rule: %w", err)
}
r.updateState()
return nil
}
// addLegacyRouteRule adds a legacy routing rule for mgmt servers pre route acls
func (r *router) addLegacyRouteRule(pair firewall.RouterPair) error {
ruleKey := firewall.GenKey(firewall.ForwardingFormat, pair)
if err := r.removeLegacyRouteRule(pair); err != nil {
return err
}
rule := []string{"-s", pair.Source.String(), "-d", pair.Destination.String(), "-j", routingFinalForwardJump}
if err := r.iptablesClient.Append(tableFilter, chainRTFWDIN, rule...); err != nil {
return fmt.Errorf("add legacy forwarding rule %s -> %s: %v", pair.Source, pair.Destination, err)View on GitHub (pinned to 93e97f4bf1)
Solutions
- Check which inner error fired ('remove legacy forwarding rule' vs 'decrement ipset counter') and follow its fix
- Verify NETBIRD-RT-FWD-IN contents: sudo iptables -S NETBIRD-RT-FWD-IN
- Run RemoveAllLegacyRouteRules path (full disconnect) to sweep leftovers
- Restart the agent to resynchronize in-memory rules with the kernel
Defensive patterns
Strategy: try-catch
Try / catch
if err := r.removeLegacyRouteRule(pair); err != nil {
log.Warnf("legacy rule cleanup failed for %s -> %s: %v", pair.Source, pair.Destination, err)
// not fatal for the main path; sweep later via RemoveAllLegacyRouteRules
} Prevention
- After management upgrades, run a full disconnect/reconnect to sweep legacy rules
- Watch for the inner error class (iptables vs ipset) before choosing a fix
- Keep r.rules and kernel state in sync by always tearing down through the agent
When it happens
Trigger: Removing a NAT/routing pair on a peer that earlier ran in legacyManagement mode (old management) and has a stored legacy forwarding rule. Fails when the iptables delete errors or when decrementing the set refcount errors (e.g. set in use, already destroyed).
Common situations: Management upgrade mid-session: peer installed legacy rules, management updated to route-ACL version, then rule removal hits a chain or set mutated by the earlier state; unclean shutdown leaving r.rules and kernel state diverged.
Related errors
- remove legacy forwarding rule %s -> %s: %v
- remove legacy forwarding rule: %v
- destroy set %s: %w
- add legacy routing rule: %w
- remove nat rule: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/febbaa4aebf2691d.
Report an issue: GitHub.