{"record":{"id":"99be3f199386bbf3","repo":"netbirdio/netbird","slug":"remove-v4-nat-rule-w","errorCode":null,"errorMessage":"remove v4 NAT rule: %w","messagePattern":"remove v4 NAT rule: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"client/firewall/iptables/manager_linux.go","lineNumber":309,"sourceCode":"\n\treturn nil\n}\n\nfunc (m *Manager) RemoveNatRule(pair firewall.RouterPair) error {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\n\tif pair.Destination.IsPrefix() && pair.Destination.Prefix.Addr().Is6() {\n\t\tif !m.hasIPv6() {\n\t\t\treturn nil\n\t\t}\n\t\treturn m.router6.RemoveNatRule(pair)\n\t}\n\n\tvar merr *multierror.Error\n\n\tif err := m.router.RemoveNatRule(pair); err != nil {\n\t\tmerr = multierror.Append(merr, fmt.Errorf(\"remove v4 NAT rule: %w\", err))\n\t}\n\n\tif m.hasIPv6() && pair.Dynamic {\n\t\tv6Pair := firewall.ToV6NatPair(pair)\n\t\tif err := m.router6.RemoveNatRule(v6Pair); err != nil {\n\t\t\tmerr = multierror.Append(merr, fmt.Errorf(\"remove v6 NAT rule: %w\", err))\n\t\t}\n\t}\n\n\treturn nberrors.FormatErrorOrNil(merr)\n}\n\nfunc (m *Manager) SetLegacyManagement(isLegacy bool) error {\n\tif err := firewall.SetLegacyManagement(m.router, isLegacy); err != nil {\n\t\treturn err\n\t}\n\tif m.hasIPv6() {\n\t\treturn firewall.SetLegacyManagement(m.router6, isLegacy)","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/manager_linux.go#L291-L327","documentation":"Best-effort teardown error: RemoveNatRule failed to delete the v4 half of a NAT pair via router.RemoveNatRule, and it was accumulated into a multierror (the v6 half is still attempted afterwards). Most commonly the underlying iptables Delete fails because the rule is already gone - chains were flushed externally or a previous Close removed them.","triggerScenarios":"RemoveNatRule(pair) on a v4-destination pair when the NETBIRD nat chains or the specific rule no longer exist, or the iptables Delete call otherwise errors; result is a *multierror.Error containing 'remove v4 NAT rule: ...'.","commonSituations":"Agent shutdown racing an external firewall rewrite; double teardown (Close called after a crash-recovery cleanup already removed rules); unprivileged close.","solutions":["Treat as idempotent cleanup: re-run RemoveNatRule or the full Close to converge","Inspect with iptables-save -t nat | grep NETBIRD to confirm no leftovers remain","If errors persist across restarts, capture the wrapped ip6tables/iptables message from the daemon log and address that layer"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := mgr.RemoveNatRule(pair); err != nil {\n    var merr *multierror.Error\n    if errors.As(err, &merr) {\n        for _, e := range merr.Errors {\n            log.Debugf(\"nat teardown partial: %v\", e) // usually 'already gone'\n        }\n        return nil // treat idempotent-teardown noise as success\n    }\n    return err\n}","preventionTips":["Treat NAT teardown errors as retryable: re-invoke removal or rely on Close","Inspect *multierror.Error to separate v4/v6 halves when diagnosing","Avoid concurrent external iptables rewrites during agent shutdown"],"tags":["iptables","firewall","nat","cleanup","netbird","go"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}