{"record":{"id":"c3170ad7f13711f7","repo":"slackhq/nebula","slug":"s-rule-v-proto-was-not-understood-s","errorCode":null,"errorMessage":"%s rule #%v; proto was not understood; `%s`","messagePattern":"(.+?) rule #(.+?); proto was not understood; `(.+?)`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"firewall.go","lineNumber":381,"sourceCode":"\t\tswitch r.Proto {\n\t\tcase \"any\":\n\t\t\tproto = firewall.ProtoAny\n\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}","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/firewall.go#L363-L399","documentation":"Within AddFirewallRulesFromConfig, each rule's \"proto\" string is matched against any/tcp/udp/icmp (case-insensitive via earlier normalization). An unrecognized proto hits the default branch and returns this error naming the table, rule index, and raw value.","triggerScenarios":"A rule whose proto is e.g. \"sctp\", \"TCP/UDP\", \"\", or any misspelled value — anything not exactly matching the supported set after normalization.","commonSituations":"Typos (\"upd\"), trying to specify protocols the firewall does not support, or leaving the proto field empty in a YAML rule.","solutions":["Set proto to one of: any, tcp, udp, or icmp.","Use proto \"any\" if the rule should match any protocol.","Check spelling and avoid combined values like \"tcp/udp\" — use two rules instead."],"exampleFix":"// before (config)\n- port: 53\n  proto: upd\n// after\n- port: 53\n  proto: udp","handlingStrategy":"validation","validationCode":"var allowedProtos = map[string]bool{\"any\": true, \"tcp\": true, \"udp\": true, \"icmp\": true}\nfunc validateProto(rules []map[string]any) error {\n    for i, r := range rules {\n        p, _ := r[\"proto\"].(string)\n        if !allowedProtos[strings.ToLower(p)] {\n            return fmt.Errorf(\"rule #%d: unsupported proto %q\", i, p)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := fw.AddFirewallRulesFromConfig(l, table, rules); err != nil {\n    if strings.Contains(err.Error(), \"proto was not understood\") {\n        log.Fatalf(\"fix proto field (any/tcp/udp/icmp): %v\", err)\n    }\n    return err\n}","preventionTips":["Restrict configs to the four supported proto values.","Avoid spelling mistakes like \"upd\" with a config linter.","Use \"any\" for protocol-agnostic rules; never combine protocols in one value."],"tags":["firewall","configuration","validation"],"backgroundTag":"invalid-protocol-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"}