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

  1. Set proto to one of: any, tcp, udp, or icmp.
  2. Use proto "any" if the rule should match any protocol.
  3. 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

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


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/c3170ad7f13711f7. Report an issue: GitHub.