slackhq/nebula · error
invalid port: %d
Error message
invalid port: %d
What it means
newCalculatedRemote stores the port in a uint32-backed field but the wire format only allows 16-bit ports, so it rejects ports below 0 or above 65535 (math.MaxUint16). This catches out-of-range ports supplied through calculated_remotes config entries.
Source
Thrown at calculated_remote.go:31
)
// This allows us to "guess" what the remote might be for a host while we wait
// for the lighthouse response. See "lighthouse.calculated_remotes" in the
// example config file.
type calculatedRemote struct {
ipNet netip.Prefix
mask netip.Prefix
port uint32
}
func newCalculatedRemote(cidr, maskCidr netip.Prefix, port int) (*calculatedRemote, error) {
if maskCidr.Addr().BitLen() != cidr.Addr().BitLen() {
return nil, fmt.Errorf("invalid mask: %s for cidr: %s", maskCidr, cidr)
}
masked := maskCidr.Masked()
if port < 0 || port > math.MaxUint16 {
return nil, fmt.Errorf("invalid port: %d", port)
}
return &calculatedRemote{
ipNet: maskCidr,
mask: masked,
port: uint32(port),
}, nil
}
func (c *calculatedRemote) String() string {
return fmt.Sprintf("CalculatedRemote(mask=%v port=%d)", c.ipNet, c.port)
}
func (c *calculatedRemote) ApplyV4(addr netip.Addr) *V4AddrPort {
// Combine the masked bytes of the "mask" IP with the unmasked bytes of the overlay IP
maskb := net.CIDRMask(c.mask.Bits(), c.mask.Addr().BitLen())
mask := binary.BigEndian.Uint32(maskb[:])
View on GitHub (pinned to dd8f660c0a)
Solutions
- Set the port to a value between 0 and 65535
- If the port came from a string, confirm it parses with strconv.Atoi and lands in uint16 range before use
- Clamp or validate the port at config-load time in the caller
Example fix
// before - mask: 10.0.0.0/8 port: 70000 // after - mask: 10.0.0.0/8 port: 4242
Defensive patterns
Strategy: validation
Validate before calling
func validPort(p any) bool {
switch v := p.(type) {
case int:
return v >= 0 && v <= 65535
case string:
n, err := strconv.Atoi(v)
return err == nil && n >= 0 && n <= 65535
}
return false
} Type guard
func isUint16Port(n int) bool { return n >= 0 && n <= math.MaxUint16 } Try / catch
cr, err := newCalculatedRemote(cidr, maskCidr, port)
if err != nil {
if strings.HasPrefix(err.Error(), "invalid port:") {
return fmt.Errorf("port %d out of range 0-65535 for %s", port, cidr)
}
return err
} Prevention
- Clamp or range-check ports against math.MaxUint16 at config boundaries
- Beware string ports that parse to values >65535 via strconv.Atoi
- Use config schema validation with a uint16 port constraint before reload
When it happens
Trigger: A calculated_remotes entry whose `port` is negative, exceeds 65535, or a string like "99999" parsed via strconv.Atoi then passed to newCalculatedRemote.
Common situations: Typo'd port numbers in nebula lighthouse config (e.g. 655360 instead of 65536), negative values from bad templating, or unquoted strings that parse to huge integers.
Related errors
- config `%s` has invalid CIDR: %s
- specific port required, got 0
- stats.host can not be empty
- stats.listen should not be empty
- stats.path should not be empty
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/3a51f9c3ccfcb3dc.
Report an issue: GitHub.