{"record":{"id":"e69bc8de29d66743","repo":"netbirdio/netbird","slug":"invalid-rule-type","errorCode":null,"errorMessage":"invalid rule type","messagePattern":"invalid rule type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/acl_linux.go","lineNumber":193,"sourceCode":"\t\truleID:      uuid.New().String(),\n\t\tspecs:       specs,\n\t\tmangleSpecs: mangleSpecs,\n\t\tipsetName:   ipsetName,\n\t\tip:          ip.String(),\n\t\tchain:       chain,\n\t\tv6:          m.v6,\n\t}\n\n\tm.updateState()\n\n\treturn []firewall.Rule{rule}, nil\n}\n\n// DeletePeerRule from the firewall by rule definition\nfunc (m *aclManager) DeletePeerRule(rule firewall.Rule) error {\n\tr, ok := rule.(*Rule)\n\tif !ok {\n\t\treturn fmt.Errorf(\"invalid rule type\")\n\t}\n\n\tshouldDestroyIpset := false\n\tif ipsetList, ok := m.ipsetStore.ipset(r.ipsetName); ok {\n\t\t// delete IP from ruleset IPs list and ipset\n\t\tif _, ok := ipsetList.ips[r.ip]; ok {\n\t\t\tip := net.ParseIP(r.ip)\n\t\t\tif ip == nil {\n\t\t\t\treturn fmt.Errorf(\"parse IP %s\", r.ip)\n\t\t\t}\n\t\t\tif err := m.delFromIPSet(r.ipsetName, ip); err != nil {\n\t\t\t\treturn fmt.Errorf(\"delete ip from ipset: %w\", err)\n\t\t\t}\n\t\t\tdelete(ipsetList.ips, r.ip)\n\t\t}\n\n\t\t// if after delete, set still contains other IPs,\n\t\t// no need to delete firewall rule and we should exit here","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/acl_linux.go#L175-L211","documentation":"DeletePeerRule performs a checked type assertion of the firewall.Rule interface to the iptables package's concrete *Rule. Passing anything else, a rule from the nftables manager, a mock, or a typed-nil *Rule wrapped in the interface, fails the assertion and returns this error. It is a programming/API-contract error, not an environment problem: rules are only meaningful to the manager implementation that created them.","triggerScenarios":"Forwarding a firewall.Rule obtained from a different backend (nftables/pf/WFP) into the iptables manager's DeletePeerRule; unit tests passing mocks or plain structs; storing rules as firewall.Rule across a manager recreation and deleting them from the new instance; deleting a nil *Rule via the interface.","commonSituations":"Firewall-manager fallback code that swaps implementations at runtime but reuses cached rules; test code exercising DeletePeerRule with hand-built rule values.","solutions":["Only pass rules returned by the same iptables Manager instance's AddPeerFiltering/AddRouteFiltering.","Keep rules stored as their concrete type or re-fetch them from the manager instead of crossing implementations.","In tests, construct rules via the real manager or export a constructor for fixtures.","Add a type switch/guard at the call site to fail fast with context."],"exampleFix":"// before\nerr := mgr.DeletePeerRule(rule) // rule came from another backend\n\n// after\nitr, ok := rule.(*iptables.Rule)\nif !ok {\n    return fmt.Errorf(\"rule %T not created by the iptables manager\", rule)\n}\nerr := mgr.DeletePeerRule(itr)","handlingStrategy":"type-guard","validationCode":"if _, ok := rule.(*iptables.Rule); !ok {\n    return fmt.Errorf(\"refusing to delete rule of type %T through the iptables manager\", rule)\n}","typeGuard":"func isIPTablesRule(r firewall.Rule) (*iptables.Rule, bool) {\n    ir, ok := r.(*iptables.Rule)\n    return ir, ok\n}","tryCatchPattern":"if err := mgr.DeletePeerRule(rule); err != nil {\n    if strings.Contains(err.Error(), \"invalid rule type\") {\n        // programmer error: rule came from another backend; drop it from tracking\n        log.Errorf(\"dropping foreign rule %T\", rule)\n    }\n}","preventionTips":["Store rules next to the manager that produced them; never move firewall.Rule values across implementations.","Return rules to the exact same manager instance that created them, especially across fallback/swap logic.","In tests, generate rules via the real manager instead of hand-building struct literals.","Prefer deleting by rule ID/handle at the engine layer rather than passing opaque Rule objects around."],"tags":["go","type-assertion","firewall","api-misuse","netbird"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}