{"record":{"id":"8d3d98024b065c8a","repo":"netbirdio/netbird","slug":"icmp-does-not-accept-ports-use-icmp-without","errorCode":null,"errorMessage":"icmp does not accept ports; use 'icmp' without '/…'","messagePattern":"icmp does not accept ports; use 'icmp' without '/…'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/management/types/policy.go","lineNumber":212,"sourceCode":"\t\treturn PolicyRuleProtocolICMP, RulePortRange{}, nil\n\t}\n\n\tsplit := strings.Split(rule, \"/\")\n\tif len(split) != 2 {\n\t\treturn \"\", RulePortRange{}, errors.New(\"invalid rule format: expected protocol/port or protocol/port-range\")\n\t}\n\n\tprotoStr := strings.TrimSpace(split[0])\n\tportStr := strings.TrimSpace(split[1])\n\n\tvar protocol PolicyRuleProtocolType\n\tswitch protoStr {\n\tcase \"tcp\":\n\t\tprotocol = PolicyRuleProtocolTCP\n\tcase \"udp\":\n\t\tprotocol = PolicyRuleProtocolUDP\n\tcase \"icmp\":\n\t\treturn \"\", RulePortRange{}, errors.New(\"icmp does not accept ports; use 'icmp' without '/…'\")\n\tcase \"netbird-ssh\":\n\t\treturn PolicyRuleProtocolNetbirdSSH, RulePortRange{Start: nativeSSHPortNumber, End: nativeSSHPortNumber}, nil\n\tdefault:\n\t\treturn \"\", RulePortRange{}, fmt.Errorf(\"invalid protocol: %q\", protoStr)\n\t}\n\n\tportRange, err := parsePortRange(portStr)\n\tif err != nil {\n\t\treturn \"\", RulePortRange{}, err\n\t}\n\n\treturn protocol, portRange, nil\n}\n\nfunc parsePortRange(portStr string) (RulePortRange, error) {\n\tif strings.Contains(portStr, \"-\") {\n\t\trangeParts := strings.Split(portStr, \"-\")\n\t\tif len(rangeParts) != 2 {","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/shared/management/types/policy.go#L194-L230","documentation":"ParseRuleString rejects 'icmp/<anything>' because ICMP has no port concept in this model; the protocol must appear bare. The error fires specifically when the protocol segment is 'icmp' and a '/'-separated port part is also present.","triggerScenarios":"Rules like icmp/8, icmp/echo-request, or icmp/0 — usually ICMP type codes written where a port would go.","commonSituations":"Porting firewall rules from tools that number ICMP types/messages; copy-pasting a tcp rule and swapping only the protocol word.","solutions":["Write 'icmp' alone with no slash or port","Express ICMP type filtering outside this parser — it does not model ICMP types"],"exampleFix":"// before\nproto, ports, err := types.ParseRuleString(\"icmp/8\")\n\n// after\nproto, ports, err := types.ParseRuleString(\"icmp\")","handlingStrategy":"validation","validationCode":"func normalizeRule(rule string) (string, error) {\n\tr := strings.ToLower(strings.TrimSpace(rule))\n\tif strings.HasPrefix(r, \"icmp/\") {\n\t\treturn \"\", fmt.Errorf(\"icmp rule %q must not carry a port; use 'icmp'\", rule)\n\t}\n\treturn r, nil\n}","typeGuard":"func isBareIcmpRule(rule string) bool {\n\treturn strings.ToLower(strings.TrimSpace(rule)) == \"icmp\"\n}","tryCatchPattern":"if _, _, err := types.ParseRuleString(rule); err != nil {\n\tif strings.Contains(err.Error(), \"icmp does not accept ports\") {\n\t\trule = \"icmp\" // strip the misplaced type code and retry\n\t}\n}","preventionTips":["Document that ICMP types are not expressible in rule strings","Strip trailing '/<digits>' when migrating ICMP rules from other firewall syntaxes","Add UI dropdowns for protocol so free-text cannot combine icmp with a port"],"tags":["policy","icmp","validation","parsing"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}