micro/go-micro · error
unable to extract port range
Error message
unable to extract port range
What it means
This error is thrown by util/net.Listen when parsing a user-supplied port range string like "8000-9000". The range is split on the separator and each half must parse as an integer via strconv.Atoi; the first half (the minimum port) failed to parse. It is a guard so the pool can know which ports to try binding.
Source
Thrown at internal/util/net/net.go:54
host, ports, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
// try to extract port range
prange := strings.Split(ports, "-")
// single port
if len(prange) < 2 {
return fn(addr)
}
// we have a port range
// extract min port
min, err := strconv.Atoi(prange[0])
if err != nil {
return nil, errors.New("unable to extract port range")
}
// extract max port
max, err := strconv.Atoi(prange[1])
if err != nil {
return nil, errors.New("unable to extract port range")
}
// range the ports
for port := min; port <= max; port++ {
// try bind to host:port
ln, err := fn(HostPort(host, port))
if err == nil {
return ln, nil
}
// hit max port
if port == max {View on GitHub (pinned to 24529f1404)
Solutions
- Check the port-range value actually passed to Listen and print it before parsing; fix the min portion so it is a plain integer (e.g. "8000-9000").
- Trim whitespace and remove stray characters before the range reaches Listen.
- If the value comes from env/config, validate it with a regex like ^[0-9]+-[0-9]+$ at startup and fail fast with a clear message.
- Use named constants or ints in config instead of a raw string to avoid formatting errors.
Example fix
// before
addr, err := net.Listen(pool, os.Getenv("PORT_RANGE")) // PORT_RANGE="8 - 9000"
// after
pr := strings.ReplaceAll(os.Getenv("PORT_RANGE"), " ", "") // "8000-9000"
if !regexp.MustCompile(`^[0-9]+-[0-9]+$`).MatchString(pr) {
return fmt.Errorf("invalid PORT_RANGE: %q", os.Getenv("PORT_RANGE"))
}
addr, err := net.Listen(pool, pr) Defensive patterns
Strategy: validation
Validate before calling
func validPortRange(s string) bool {
parts := strings.Split(s, "-")
if len(parts) != 2 { return false }
min, err1 := strconv.Atoi(strings.TrimSpace(parts[0]))
max, err2 := strconv.Atoi(strings.TrimSpace(parts[1]))
return err1 == nil && err2 == nil && min <= max && min > 0 && max <= 65535
} Type guard
func isPortRange(s string) (min, max int, ok bool) {
parts := strings.Split(s, "-")
if len(parts) != 2 { return 0, 0, false }
var e1, e2 error
min, e1 = strconv.Atoi(strings.TrimSpace(parts[0]))
max, e2 = strconv.Atoi(strings.TrimSpace(parts[1]))
return min, max, e1 == nil && e2 == nil
} Try / catch
addr, err := net.Listen(pool, prange)
if err != nil {
if strings.Contains(err.Error(), "unable to extract port range") {
return fmt.Errorf("malformed PORT_RANGE %q: want e.g. 8000-9000", prange)
}
return err
} Prevention
- Validate port-range strings with a regex at config-load time
- Trim whitespace and normalize dashes (replace unicode – with -) before use
- Store port ranges as two integers instead of one string
- Log the exact value passed to Listen on failure
When it happens
Trigger: Calling Listen (directly or via a pool that resolves free ports) with a port range whose min portion is not a valid integer, e.g. MIN_PORT unset so the range string is "-9000", or "8000 -9000" with stray spaces, or a reversed/garbled range like "x-9000".
Common situations: Misconfigured environment variables or config files for port ranges (MIN_PORT/MAX_PORT); YAML/JSON values quoted or containing whitespace; empty string producing a split with a non-numeric element; platform-specific startup scripts exporting malformed values.
Related errors
- agent: ResumeStreamAsk requires a checkpoint
- API error: nil response
- ai model is nil
- no secret key is defined
- Cannot use two forms of the same flag: <name> <ff.Name>
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/787c4fb178c9b975.
Report an issue: GitHub.