slackhq/nebula · error
unknown protocol %v
Error message
unknown protocol %v
What it means
AddRule on the firewall validates the protocol of a new rule. Only tcp, udp, icmp, and any are supported; anything else falls through to the default case and returns this error. The rule is not installed when this occurs.
Source
Thrown at firewall.go:281
}
switch proto {
case iputil.IPProtocolTCP:
fp = ft.TCP
case iputil.IPProtocolUDP:
fp = ft.UDP
case iputil.IPProtocolICMP, iputil.IPProtocolICMPv6:
//ICMP traffic doesn't have ports, so we always coerce to "any", even if a value is provided
if startPort != firewall.PortAny {
f.l.Warn("ignoring port specification for ICMP firewall rule", "startPort", startPort)
}
startPort = firewall.PortAny
endPort = firewall.PortAny
fp = ft.ICMP
case firewall.ProtoAny:
fp = ft.AnyProto
default:
return fmt.Errorf("unknown protocol %v", proto)
}
// We need this rule string because we generate a hash. Removing this will break firewall reload.
ruleString := fmt.Sprintf(
"incoming: %v, proto: %v, startPort: %v, endPort: %v, groups: %v, host: %v, ip: %v, localIp: %v, caName: %v, caSha: %s",
incoming, proto, startPort, endPort, groups, host, cidr, localCidr, caName, caSha,
)
f.rules += ruleString + "\n"
direction := "incoming"
if !incoming {
direction = "outgoing"
}
f.l.Info("Firewall rule added",
"firewallRule", m{"direction": direction, "proto": proto, "startPort": startPort, "endPort": endPort, "groups": groups, "host": host, "cidr": cidr, "localCidr": localCidr, "caName": caName, "caSha": caSha},
)
return fp.addRule(f, startPort, endPort, groups, host, cidr, localCidr, caName, caSha)View on GitHub (pinned to dd8f660c0a)
Solutions
- Use one of the supported protocols: tcp, udp, icmp, or any.
- If you need a rule that matches all traffic, use ProtoAny instead of an invented value.
- Normalize/validate the proto string from config before constructing the rule (config parsing normally lowercases it via convertRule).
Example fix
// before
fw.AddRule(true, firewall.Proto("http"), 0, 443, []string{"app"}, "", nil, nil, nil, "", "")
// after
fw.AddRule(true, firewall.ProtoTCP, 0, 443, []string{"app"}, "", nil, nil, nil, "", "") Defensive patterns
Strategy: validation
Validate before calling
var validProtos = map[firewall.Protocol]bool{
firewall.ProtoTCP: true, firewall.ProtoUDP: true,
firewall.ProtoICMP: true, firewall.ProtoAny: true,
}
if !validProtos[proto] {
return fmt.Errorf("unsupported proto %q; use tcp, udp, icmp, or any", proto)
}
err := fw.AddRule(true, proto, 0, 443, groups, "", nil, nil, nil, "", "") Type guard
func isSupportedProto(p firewall.Protocol) bool {
switch p {
case firewall.ProtoTCP, firewall.ProtoUDP, firewall.ProtoICMP, firewall.ProtoAny:
return true
}
return false
} Try / catch
if err := fw.AddRule(true, proto, start, end, groups, "", nil, nil, nil, "", ""); err != nil {
if strings.Contains(err.Error(), "unknown protocol") {
log.Fatalf("proto %v not supported; use tcp/udp/icmp/any", proto)
}
return err
} Prevention
- Only use the library's exported proto constants, never raw strings cast to Protocol.
- Normalize config proto values to lowercase before mapping them to constants.
- Add a config lint step that checks proto values against the supported set.
When it happens
Trigger: Calling firewall.AddRule with a FirewallProtocol value other than ProtoTCP, ProtoUDP, ProtoICMP, or ProtoAny (e.g. an unvalidated value read from config or a zero-value custom constant).
Common situations: Typo in a firewall rule's "proto" field in the Nebula config YAML (e.g. "http" instead of "tcp"), programmatic rule construction with a wrong constant, or parsing raw user input into a proto value without validation.
Related errors
- %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,
- %s rule #%v; proto was not understood; `%s`
- ErrInvalidLocalIP
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/9f1391dadd303b32.
Report an issue: GitHub.