slackhq/nebula · error

%s rule #%v; %s %s

Error message

%s rule #%v; %s %s

What it means

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.

Source

Thrown at firewall.go:384

			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)
			}
		}

		if warning := r.sanity(); warning != nil {
			l.Warn("firewall rule sanity check",

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Use a numeric port string in 0-65535 (e.g. "443"); use "any" for all ports.
  2. For ICMP rules, ensure "code" is a valid numeric code and remove "port".
  3. Split multi-port needs into multiple rules.

Example fix

// before (config)
- port: https
  proto: tcp
// after
- port: 443
  proto: tcp
Defensive patterns

Strategy: validation

Validate before calling

func validatePortField(rules []map[string]any) error {
    for i, r := range rules {
        for _, k := range []string{"port", "code"} {
            v, ok := r[k].(string)
            if !ok || v == "" || v == "any" { continue }
            n, err := strconv.Atoi(v)
            if err != nil || n < 0 || n > 65535 {
                return fmt.Errorf("rule #%d: %s %q must be 0-65535 or \"any\"", i, k, v)
            }
        }
    }
    return nil
}

Try / catch

if err := fw.AddFirewallRulesFromConfig(l, "inbound", rules); err != nil {
    var portErr bool
    if strings.Contains(err.Error(), " port ") || strings.Contains(err.Error(), " code ") {
        portErr = true
    }
    if portErr { log.Fatalf("numeric port/code required: %v", err) }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: Using service names instead of numeric ports, unquoted YAML values interpreted oddly, copy-pasting port ranges, or typos in the port number.

Related errors


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