gohugoio/hugo · critical
unable to find alternative port to use: %s
Error message
unable to find alternative port to use: %s
What it means
When the desired port is busy and the user did not explicitly pin it, Hugo prints a notice and asks the OS for any free port via `helpers.TCPListen()` (listen on port 0). This error means even that fallback failed — the OS refused to hand out an ephemeral port, which indicates a system-level networking problem rather than a Hugo misconfiguration.
Source
Thrown at commands/server.go:780
return
}
c.serverPorts = make([]serverPortListener, len(conf.configs.Languages))
}
currentServerPort := c.serverPort
for i := range c.serverPorts {
l, err := net.Listen("tcp", net.JoinHostPort(c.serverInterface, strconv.Itoa(currentServerPort)))
if err == nil {
c.serverPorts[i] = serverPortListener{ln: l, p: currentServerPort}
} else {
if i == 0 && flags.Changed("port") {
// port set explicitly by user -- he/she probably meant it!
cerr = fmt.Errorf("server startup failed: %s", err)
return
}
c.r.Println("port", currentServerPort, "already in use, attempting to use an available port")
l, sp, err := helpers.TCPListen()
if err != nil {
cerr = fmt.Errorf("unable to find alternative port to use: %s", err)
return
}
c.serverPorts[i] = serverPortListener{ln: l, p: sp.Port}
}
currentServerPort = c.serverPorts[i].p + 1
}
})
return cerr
}
// fixURL massages the baseURL into a form needed for serving
// all pages correctly.
func (c *serverCommand) fixURL(baseURLFromConfig, baseURLFromFlag string, port int) (string, error) {
certsSet := (c.tlsCertFile != "" && c.tlsKeyFile != "") || c.tlsAuto
useLocalhost := false
baseURL := baseURLFromFlagView on GitHub ↗ (pinned to 8a468df065)
Solutions
- Check system health: `ulimit -n`, count of open sockets (`ss -s`), and whether loopback is up.
- Free sockets/processes hogging the ephemeral range, or wait for TIME_WAIT sockets to drain.
- In containers/sandboxes, grant network-listen capability or run the server outside the sandbox.
- Retry with an explicit free port (`-p <n>`) to bypass the ephemeral allocation path.
Defensive patterns
Strategy: fallback
Validate before calling
ln, err := net.Listen("tcp", ":0") // confirm the OS can still hand out ephemeral ports
if err != nil { return err }
ln.Close() Try / catch
if err := startServer(); err != nil && strings.Contains(err.Error(), "alternative port") {
// fall back to an explicit known-free port
err = startServerWithFlag("--port", "1414")
} Prevention
- Pass an explicit --port you know is free instead of relying on auto-selection
- Clean up orphaned dev-server processes (they exhaust the probe range)
- In containers/CI, ensure the network namespace permits listening sockets
When it happens
Trigger: During `hugo server` startup after the default/derived port was in use: the fallback `net.Listen("tcp", ":0")` fails — ephemeral port range exhausted, per-process fd limit reached, no networking stack available, or sandbox/container policies blocking listeners.
Common situations: Heavily loaded CI machines or dev boxes with thousands of sockets in TIME_WAIT; restrictive sandboxes/seccomp profiles or minimal containers without network permission; extremely low `ulimit -n`; broken loopback interface.
Related errors
- server startup failed: %s
- cannot use --renderToMemory with --destination
- failed to create baseURL from %q: %s
- failed to parse root certificate
- failed to parse certificate PEM
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/765b7ea5bee29694.json.
Report an issue: GitHub ↗.