slackhq/nebula · error
%s rule #%v; proto was not understood; `%s`
Error message
%s rule #%v; proto was not understood; `%s`
What it means
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.
Source
Thrown at firewall.go:381
switch r.Proto {
case "any":
proto = firewall.ProtoAny
startPort, endPort, err = parsePort(sPort)
case "tcp":
proto = iputil.IPProtocolTCP
startPort, endPort, err = parsePort(sPort)
case "udp":
proto = iputil.IPProtocolUDP
startPort, endPort, err = parsePort(sPort)
case "icmp":
proto = iputil.IPProtocolICMP
startPort = firewall.PortAny
endPort = firewall.PortAny
if sPort != "" {
l.Warn("ignoring port specification for ICMP firewall rule", "port", sPort)
}
default:
return fmt.Errorf("%s rule #%v; proto was not understood; `%s`", table, i, r.Proto)
}
if err != nil {
return fmt.Errorf("%s rule #%v; %s %s", table, i, errPort, err)
}
if r.Cidr != "" && r.Cidr != "any" {
_, err = netip.ParsePrefix(r.Cidr)
if err != nil {
return fmt.Errorf("%s rule #%v; cidr did not parse; %s", table, i, err)
}
}
if r.LocalCidr != "" && r.LocalCidr != "any" {
_, err = netip.ParsePrefix(r.LocalCidr)
if err != nil {
return fmt.Errorf("%s rule #%v; local_cidr did not parse; %s", table, i, err)
}
}View on GitHub (pinned to dd8f660c0a)
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.
Example fix
// before (config) - port: 53 proto: upd // after - port: 53 proto: udp
Defensive patterns
Strategy: validation
Validate before calling
var allowedProtos = map[string]bool{"any": true, "tcp": true, "udp": true, "icmp": true}
func validateProto(rules []map[string]any) error {
for i, r := range rules {
p, _ := r["proto"].(string)
if !allowedProtos[strings.ToLower(p)] {
return fmt.Errorf("rule #%d: unsupported proto %q", i, p)
}
}
return nil
} Try / catch
if err := fw.AddFirewallRulesFromConfig(l, table, rules); err != nil {
if strings.Contains(err.Error(), "proto was not understood") {
log.Fatalf("fix proto field (any/tcp/udp/icmp): %v", err)
}
return err
} Prevention
- 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.
When it happens
Trigger: A rule whose proto is e.g. "sctp", "TCP/UDP", "", or any misspelled value — anything not exactly matching the supported set after normalization.
Common situations: Typos ("upd"), trying to specify protocols the firewall does not support, or leaving the proto field empty in a YAML rule.
Related errors
- unknown protocol %v
- %s failed to parse, should be an array of rules
- %s rule #%v; only one of port or code should be provided
- %s rule #%v; at least one of host, group, cidr, local_cidr,
- ErrInvalidLocalIP
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/c3170ad7f13711f7.
Report an issue: GitHub.