{"record":{"id":"0f7d6aefa29ec99a","repo":"netbirdio/netbird","slug":"remove-nat-rule-w","errorCode":null,"errorMessage":"remove nat rule: %w","messagePattern":"remove nat rule: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/router_linux.go","lineNumber":295,"sourceCode":"\n\tif err := r.addNatRule(pair); err != nil {\n\t\treturn fmt.Errorf(\"add nat rule: %w\", err)\n\t}\n\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 {","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/router_linux.go#L277-L313","documentation":"Returned by router.RemoveNatRule when removeNatRule(pair) fails. It looks up the rule spec stored under GenKey(NatFormat, pair) and calls DeleteIfExists on the NETBIRD-RT-PRE mangle chain, then decrements the ipset refcounter. The wrap fires on the DeleteIfExists error; failure aborts before updateState, leaving the in-memory map consistent but the rule possibly still in the chain.","triggerScenarios":"Removing a masqueraded route/exit-node pair (netbird down, route update, management push). DeleteIfExists rarely fails: xtables lock contention, iptables binary swapped between legacy/nft backends mid-run, or security modules denying exec.","commonSituations":"Host where iptables was switched from legacy to nft backend (update-alternatives) after agent start; heavy parallel iptables activity by config management (puppet/ansible firewall modules).","solutions":["Retry removal after a short delay (lock contention is transient)","Verify leftover marks: sudo iptables -t mangle -S NETBIRD-RT-PRE and delete stragglers manually if needed","Keep one iptables backend; restart the agent after switching legacy/nft","Re-run 'sudo netbird down' to drive full teardown"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := r.removeNatRule(pair); err != nil {\n\t// DeleteIfExists is idempotent; transient lock errors clear on retry\n\treturn fmt.Errorf(\"remove nat rule: %w\", err)\n}","preventionTips":["Do not switch iptables legacy/nft alternatives while the daemon runs","Complete teardown with 'netbird down' rather than killing the process","Check for leftover MARK rules after failed removals"],"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"}