cilium/cilium · error

Unable to parse max port value %s for ephemeral range: %w

Error message

Unable to parse max port value %s for ephemeral range: %w

What it means

During kube-proxy replacement initialization, Cilium reads /proc/sys/net/ipv4/ip_local_port_range (an "MIN MAX" string) and parses both bounds. This error means the second (max) value of the ephemeral port range could not be converted to an integer with strconv.Atoi. It wraps the underlying strconv parse error (%w) so the bad token and root cause are both visible.

Source

Thrown at pkg/kpr/initializer/kube_proxy_replacement.go:385

// Otherwise, if EnableAutoProtectNodePortRange == true, then append the nodeport
// range to ip_local_reserved_ports.
func checkNodePortAndEphemeralPortRanges(lbConfig loadbalancer.Config, sysctl sysctl.Sysctl) error {
	ephemeralPortRangeStr, err := sysctl.Read([]string{"net", "ipv4", "ip_local_port_range"})
	if err != nil {
		return fmt.Errorf("Unable to read net.ipv4.ip_local_port_range: %w", err)
	}
	ephemeralPortRange := strings.Split(ephemeralPortRangeStr, "\t")
	if len(ephemeralPortRange) != 2 {
		return fmt.Errorf("Invalid ephemeral port range: %s", ephemeralPortRangeStr)
	}
	ephemeralPortMin, err := strconv.Atoi(ephemeralPortRange[0])
	if err != nil {
		return fmt.Errorf("Unable to parse min port value %s for ephemeral range: %w",
			ephemeralPortRange[0], err)
	}
	ephemeralPortMax, err := strconv.Atoi(ephemeralPortRange[1])
	if err != nil {
		return fmt.Errorf("Unable to parse max port value %s for ephemeral range: %w",
			ephemeralPortRange[1], err)
	}

	if lbConfig.NodePortMax < uint16(ephemeralPortMin) {
		// ephemeral port range does not clash with nodeport range
		return nil
	}

	nodePortRangeStr := fmt.Sprintf("%d-%d", lbConfig.NodePortMin,
		lbConfig.NodePortMax)

	if lbConfig.NodePortMin > uint16(ephemeralPortMax) {
		return fmt.Errorf("NodePort port range (%s) is not allowed to be after ephemeral port range (%s)",
			nodePortRangeStr, ephemeralPortRangeStr)
	}

	reservedPortsStr, err := sysctl.Read([]string{"net", "ipv4", "ip_local_reserved_ports"})
	if err != nil {

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Read 'cat /proc/sys/net/ipv4/ip_local_port_range' and reset it with 'sysctl -w net.ipv4.ip_local_port_range="32768 60999"' if malformed
  2. Check the wrapped error and quoted value in the message to identify the non-numeric token
  3. If in a container, ensure the host sysctl is visible/mounted and not overridden by an empty value

Example fix

// before (test fake sysctl)
sysctl := mapsysctl.NewMapSysCtl(t, map[string]string{"net/ipv4/ip_local_port_range": "32768 bogus"})
// after
sysctl := mapsysctl.NewMapSysCtl(t, map[string]string{"net/ipv4/ip_local_port_range": "32768 60999"})
Defensive patterns

Strategy: validation

Validate before calling

const ipLocalPortRange = "/proc/sys/net/ipv4/ip_local_port_range"
b, err := os.ReadFile(ipLocalPortRange)
if err != nil { return err }
fields := strings.Fields(string(b))
if len(fields) != 2 {
    return fmt.Errorf("malformed %s: %q", ipLocalPortRange, string(b))
}
for _, f := range fields {
    if _, err := strconv.Atoi(f); err != nil {
        return fmt.Errorf("non-numeric token %q in %s: %w", f, ipLocalPortRange, err)
    }
}

Type guard

func validPortRange(s string) bool {
    fields := strings.Fields(s)
    if len(fields) != 2 { return false }
    _, err1 := strconv.Atoi(fields[0])
    _, err2 := strconv.Atoi(fields[1])
    return err1 == nil && err2 == nil
}

Try / catch

if err := checkNodePortAndEphemeralPortRanges(lbConfig, sysctl); err != nil {
    var numErr *strconv.NumError
    if errors.As(err, &numErr) {
        log.Fatalf("malformed ephemeral port range sysctl (bad token %q): fix net.ipv4.ip_local_port_range", numErr.Num)
    }
    return err
}

Prevention

When it happens

Trigger: checkNodePortAndEphemeralPortRanges splits the value of net.ipv4.ip_local_port_range on whitespace and calls strconv.Atoi on ephemeralPortRange[1]; it fails when the kernel-side value is non-numeric, empty, or malformed (e.g. range file contents missing the max token).

Common situations: Corrupted or unusually formatted /proc/sys/net/ipv4/ip_local_port_range on a node; running in an environment (container, minimal OS) where the sysctl is empty or stubbed; a test harness providing a fake sysctl with a bad range string like "32768 abc".

Understand the failure class

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/e31bcb1eeee4c5d0. Report an issue: GitHub.