{"record":{"id":"787780137d421fbe","repo":"netbirdio/netbird","slug":"remove-inverse-nat-rule-w","errorCode":null,"errorMessage":"remove inverse nat rule: %w","messagePattern":"remove inverse nat rule: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/router_linux.go","lineNumber":299,"sourceCode":"\n\tif err := r.addNatRule(firewall.GetInversePair(pair)); err != nil {\n\t\treturn fmt.Errorf(\"add inverse nat rule: %w\", err)\n\t}\n\n\tr.updateState()\n\n\treturn nil\n}\n\n// RemoveNatRule removes an iptables rule pair from forwarding and nat chains\nfunc (r *router) RemoveNatRule(pair firewall.RouterPair) error {\n\tif pair.Masquerade {\n\t\tif err := r.removeNatRule(pair); err != nil {\n\t\t\treturn fmt.Errorf(\"remove nat rule: %w\", err)\n\t\t}\n\n\t\tif err := r.removeNatRule(firewall.GetInversePair(pair)); err != nil {\n\t\t\treturn fmt.Errorf(\"remove inverse nat rule: %w\", err)\n\t\t}\n\t}\n\n\tif err := r.removeLegacyRouteRule(pair); err != nil {\n\t\treturn fmt.Errorf(\"remove legacy routing rule: %w\", err)\n\t}\n\n\tr.updateState()\n\n\treturn nil\n}\n\n// addLegacyRouteRule adds a legacy routing rule for mgmt servers pre route acls\nfunc (r *router) addLegacyRouteRule(pair firewall.RouterPair) error {\n\truleKey := firewall.GenKey(firewall.ForwardingFormat, pair)\n\n\tif err := r.removeLegacyRouteRule(pair); err != nil {\n\t\treturn err","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/router_linux.go#L281-L317","documentation":"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.","triggerScenarios":"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.","commonSituations":"Concurrent teardown paths (netbird down while management pushes a route update); manual iptables -t mangle -F NETBIRD-RT-PRE between the two deletes.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := r.removeNatRule(firewall.GetInversePair(pair)); err != nil {\n\t// retry once: the forward leg is already gone, inverse delete is idempotent\n\treturn fmt.Errorf(\"remove inverse nat rule: %w\", err)\n}","preventionTips":["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'"],"tags":["iptables","nat","cleanup","linux","netbird"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}