slackhq/nebula · error

start port was lower than end port

Error message

start port was lower than end port

What it means

firewallPort.addRule rejects any rule where startPort > endPort. Ranges must be ascending and inclusive; a descending range would install zero rules silently, so the library fails fast instead. The error is usually wrapped by AddFirewallRulesFromConfig with the table and rule index.

Solutions

  1. Swap the range so start <= end (port: '50-100')
  2. If using config, reorder the range values in the port field
  3. If calling AddRule programmatically, sort the ports before passing them

Example fix

// before
fw.AddRule(true, proto, 8080, 80, ...)
// after
fw.AddRule(true, proto, 80, 8080, ...)
Defensive patterns

Strategy: validation

Validate before calling

func checkPorts(start, end int32) error {
    if start > end {
        return fmt.Errorf("start port %d is greater than end port %d", start, end)
    }
    return nil
}

Type guard

func ascendingRange(start, end int32) (int32, int32, bool) {
    if start <= end { return start, end, true }
    return end, start, false // false signals the caller had them swapped
}

Try / catch

if err := fw.AddRule(inbound, proto, start, end, ...); err != nil {
    if strings.Contains(err.Error(), "start port was lower than end port") {
        start, end = end, start // or surface a config bug
    }
    return err
}

Prevention

When it happens

Trigger: fw.AddRule (via firewallPort.addRule) called with startPort > endPort, e.g. port range '100-50' from config, or a programmatic AddRule call with swapped arguments.

Common situations: Typo'd YAML port ranges written high-to-low; copy-pasted ranges with values swapped; code that computes min/max in the wrong order.

Related errors


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

Appendix: source

Thrown at firewall.go:658

		if ft.TCP.match(p, incoming, c, caPool) {
			return true
		}
	case iputil.IPProtocolUDP:
		if ft.UDP.match(p, incoming, c, caPool) {
			return true
		}
	case iputil.IPProtocolICMP, iputil.IPProtocolICMPv6:
		if ft.ICMP.match(p, incoming, c, caPool) {
			return true
		}
	}

	return false
}

func (fp firewallPort) addRule(f *Firewall, startPort int32, endPort int32, groups []string, host string, cidr, localCidr, caName string, caSha string) error {
	if startPort > endPort {
		return fmt.Errorf("start port was lower than end port")
	}

	for i := startPort; i <= endPort; i++ {
		if _, ok := fp[i]; !ok {
			fp[i] = &FirewallCA{
				CANames: make(map[string]*FirewallRule),
				CAShas:  make(map[string]*FirewallRule),
			}
		}

		if err := fp[i].addRule(f, groups, host, cidr, localCidr, caName, caSha); err != nil {
			return err
		}
	}

	return nil
}

View on GitHub (pinned to dd8f660c0a)