{"record":{"id":"9d60a143569ab899","repo":"netbirdio/netbird","slug":"parse-ip-s","errorCode":null,"errorMessage":"parse IP %s","messagePattern":"parse IP (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/acl_linux.go","lineNumber":202,"sourceCode":"\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\n\t\tif len(ipsetList.ips) != 0 {\n\t\t\treturn nil\n\t\t}\n\n\t\t// we delete last IP from the set, that means we need to delete\n\t\t// set itself and associated firewall rule too\n\t\tm.ipsetStore.deleteIpset(r.ipsetName)\n\t\tshouldDestroyIpset = true\n\t}","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/acl_linux.go#L184-L220","documentation":"While deleting a peer rule, net.ParseIP of the Rule's stored ip string returned nil, so the string is not a valid IPv4 or IPv6 literal. In normal operation ip is produced by ip.String() and always parses; a failure therefore means the Rule was constructed outside the manager with a corrupted, empty, or malformed address (e.g. a CIDR like 10.0.0.1/32 instead of a bare IP).","triggerScenarios":"Hand-built Rule values in tests or restored state that carry \"10.0.0.1/32\", \"\", a hostname, or whitespace; serialization round-trips that mangle the field; rules copied from the routemanager where prefixes are the native format.","commonSituations":"Test fixtures written by hand; persistence layers that store prefix notation; refactors that changed the field's expected format without updating all constructors.","solutions":["Always create rules through AddPeerFiltering so ip is set from net.IP.String().","Validate the field at construction: reject anything net.ParseIP cannot parse, and store bare addresses, never CIDRs.","If restoring rules from persisted state, re-parse with netip.ParsePrefix and pass .Addr().String() when the value carries a prefix."],"exampleFix":"// before\nip := net.ParseIP(r.ip) // r.ip == \"10.0.0.1/32\" -> nil\n\n// after (normalize at the boundary)\naddr, err := netip.ParseAddr(r.ip)\nif err != nil {\n    if p, perr := netip.ParsePrefix(r.ip); perr == nil {\n        addr = p.Addr()\n    } else {\n        return fmt.Errorf(\"parse IP %s: %w\", r.ip, err)\n    }\n}","handlingStrategy":"validation","validationCode":"if net.ParseIP(candidateIP) == nil {\n    return fmt.Errorf(\"%q is not a valid IP literal; refusing to build a rule\", candidateIP)\n}","typeGuard":"func isValidRuleIP(s string) bool { return net.ParseIP(s) != nil }","tryCatchPattern":"if err := mgr.DeletePeerRule(rule); err != nil {\n    if strings.Contains(err.Error(), \"parse IP\") {\n        // corrupted rule record: drop it locally instead of retrying\n        removeRuleFromState(rule)\n    }\n}","preventionTips":["Always derive Rule.ip from net.IP.String() at creation time.","Never store CIDR prefixes in the ip field; normalize with netip.ParsePrefix(...).Addr().String() at boundaries.","Validate persisted rule records with net.ParseIP before replaying deletes after a restart.","Write tests that round-trip rule state through your persistence format to catch mangling early."],"tags":["go","ip-parsing","firewall","data-corruption","validation"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}