netbirdio/netbird · error
remove inverse nat rule: %w
Error message
remove inverse nat rule: %w
What it means
Returned by router.RemoveNatRule when removeNatRule(firewall.GetInversePair(pair)) fails: deleting the inverse (return-traffic MARK) rule from NETBIRD-RT-PRE. Mechanically identical to error 546 but for the '!' -i <iface> leg of the pair; if it fails after the forward leg was deleted, the pair is half-removed.
Source
Thrown at client/firewall/iptables/router_linux.go:299
if err := r.addNatRule(firewall.GetInversePair(pair)); err != nil {
return fmt.Errorf("add inverse nat rule: %w", err)
}
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 errView on GitHub (pinned to 93e97f4bf1)
Solutions
- Retry RemoveNatRule; DeleteIfExists tolerates an already-absent rule so the retry converges
- Inspect 'iptables -t mangle -S NETBIRD-RT-PRE' for leftover return-mark rules and remove them
- Avoid manual flushes of NETBIRD-* chains while the agent runs
- Restart the agent if the iptables backend was changed on the host
Defensive patterns
Strategy: retry
Try / catch
if err := r.removeNatRule(firewall.GetInversePair(pair)); err != nil {
// retry once: the forward leg is already gone, inverse delete is idempotent
return fmt.Errorf("remove inverse nat rule: %w", err)
} Prevention
- Never flush NETBIRD-RT-PRE manually mid-operation
- Serialize route updates from management (single engine goroutine)
- Verify pair removal with 'iptables -t mangle -S NETBIRD-RT-PRE'
When it happens
Trigger: Removing a masquerading pair where the forward DeleteIfExists succeeded but the inverse one hit an iptables error: lock contention, backend switch, or the chain having been flushed out-of-band so DeleteIfExists semantics changed underneath.
Common situations: Concurrent teardown paths (netbird down while management pushes a route update); manual iptables -t mangle -F NETBIRD-RT-PRE between the two deletes.
Related errors
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/787780137d421fbe.
Report an issue: GitHub.