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
- 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
- Check the wrapped error and quoted value in the message to identify the non-numeric token
- 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
- Persist a known-good ip_local_port_range in /etc/sysctl.d/ on all nodes
- Verify 'cat /proc/sys/net/ipv4/ip_local_port_range' outputs two integers before installing Cilium
- In tests, always populate fake sysctl maps with realistic 'MIN MAX' strings
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid reserved ports range %q
- Unable to parse reserved port %q: %w
- Unable to parse reserved port %q
- Invalid reserved ports range %q: start must be less than or
- NodePort port range (%s) must not clash with ephemeral port
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/e31bcb1eeee4c5d0.
Report an issue: GitHub.