{"record":{"id":"77502146a60475fa","repo":"slackhq/nebula","slug":"s-rule-v-s-s","errorCode":null,"errorMessage":"%s rule #%v; %s %s","messagePattern":"(.+?) rule #(.+?); (.+?) (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"firewall.go","lineNumber":384,"sourceCode":"\t\t\tstartPort, endPort, err = parsePort(sPort)\n\t\tcase \"tcp\":\n\t\t\tproto = iputil.IPProtocolTCP\n\t\t\tstartPort, endPort, err = parsePort(sPort)\n\t\tcase \"udp\":\n\t\t\tproto = iputil.IPProtocolUDP\n\t\t\tstartPort, endPort, err = parsePort(sPort)\n\t\tcase \"icmp\":\n\t\t\tproto = iputil.IPProtocolICMP\n\t\t\tstartPort = firewall.PortAny\n\t\t\tendPort = firewall.PortAny\n\t\t\tif sPort != \"\" {\n\t\t\t\tl.Warn(\"ignoring port specification for ICMP firewall rule\", \"port\", sPort)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"%s rule #%v; proto was not understood; `%s`\", table, i, r.Proto)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%s rule #%v; %s %s\", table, i, errPort, err)\n\t\t}\n\n\t\tif r.Cidr != \"\" && r.Cidr != \"any\" {\n\t\t\t_, err = netip.ParsePrefix(r.Cidr)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"%s rule #%v; cidr did not parse; %s\", table, i, err)\n\t\t\t}\n\t\t}\n\n\t\tif r.LocalCidr != \"\" && r.LocalCidr != \"any\" {\n\t\t\t_, err = netip.ParsePrefix(r.LocalCidr)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"%s rule #%v; local_cidr did not parse; %s\", table, i, err)\n\t\t\t}\n\t\t}\n\n\t\tif warning := r.sanity(); warning != nil {\n\t\t\tl.Warn(\"firewall rule sanity check\",","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/firewall.go#L366-L402","documentation":"After proto validation, AddFirewallRulesFromConfig parses the rule's port (or ICMP code) value into startPort/endPort. If that parsing fails, the error is wrapped as \"<table> rule #<index>; <port|code> <err>\" indicating which field failed and why.","triggerScenarios":"A rule with a non-numeric or out-of-range port/code, e.g. port: \"https\", port: \"70000\", or port: \"80-90\" where ranged/shorthand forms are not accepted here.","commonSituations":"Using service names instead of numeric ports, unquoted YAML values interpreted oddly, copy-pasting port ranges, or typos in the port number.","solutions":["Use a numeric port string in 0-65535 (e.g. \"443\"); use \"any\" for all ports.","For ICMP rules, ensure \"code\" is a valid numeric code and remove \"port\".","Split multi-port needs into multiple rules."],"exampleFix":"// before (config)\n- port: https\n  proto: tcp\n// after\n- port: 443\n  proto: tcp","handlingStrategy":"validation","validationCode":"func validatePortField(rules []map[string]any) error {\n    for i, r := range rules {\n        for _, k := range []string{\"port\", \"code\"} {\n            v, ok := r[k].(string)\n            if !ok || v == \"\" || v == \"any\" { continue }\n            n, err := strconv.Atoi(v)\n            if err != nil || n < 0 || n > 65535 {\n                return fmt.Errorf(\"rule #%d: %s %q must be 0-65535 or \\\"any\\\"\", i, k, v)\n            }\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := fw.AddFirewallRulesFromConfig(l, \"inbound\", rules); err != nil {\n    var portErr bool\n    if strings.Contains(err.Error(), \" port \") || strings.Contains(err.Error(), \" code \") {\n        portErr = true\n    }\n    if portErr { log.Fatalf(\"numeric port/code required: %v\", err) }\n    return err\n}","preventionTips":["Always use numeric port literals, never service names like \"https\".","Quote port values in YAML so they decode as strings.","Keep ports in 1-65535; use \"any\" for wildcard."],"tags":["firewall","configuration","ports"],"backgroundTag":"invalid-port-value","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}