gohugoio/hugo · error
server startup failed: %s
Error message
server startup failed: %s
What it means
Hugo tried to bind its TCP listener on the interface/port you explicitly requested and `net.Listen` failed. Because the `--port` flag was set by the user (flag marked Changed for the first listener), Hugo treats the intent as deliberate and fails instead of silently picking another port; the underlying OS error (e.g. `address already in use`, `permission denied`) is included.
Source
Thrown at commands/server.go:774
c.withConf(func(conf *commonConfig) {
isMultihost := conf.configs.IsMultihost
c.serverPorts = make([]serverPortListener, 1)
if isMultihost {
if !c.serverAppend {
cerr = errors.New("--appendPort=false not supported when in multihost mode")
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
}
View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Free the port: find the holder with `lsof -i :<port>` / `ss -ltnp` and stop it, or pick another port with `-p`.
- Omit `--port` entirely — without an explicit port, Hugo automatically falls back to a free port.
- For privileged ports, use a port ≥1024 or run behind a proxy instead of elevating Hugo.
- Verify the `--bind` address exists on this host (common in Docker/WSL setups).
Example fix
# before hugo server -p 1313 # error: listen tcp 127.0.0.1:1313: bind: address already in use # after hugo server -p 1314 # or: hugo server (auto-picks a free port)
Defensive patterns
Strategy: retry
Validate before calling
// check the port is free before starting
ln, err := net.Listen("tcp", net.JoinHostPort(iface, port))
if err != nil { return fmt.Errorf("port %s unavailable: %w", port, err) }
ln.Close() Try / catch
if err := startServer(); err != nil {
// retry once on a different port or after freeing the conflicting process
log.Printf("startup failed: %v — retrying on alternate port", err)
err = startServerOnPort(altPort)
} Prevention
- Kill stale hugo/dev-server processes holding the port before restart
- Bind to 127.0.0.1 unless LAN exposure is intended; privileged ports (<1024) need elevated rights
- Log and inspect the wrapped error — it usually names the bind failure
When it happens
Trigger: `hugo server --port <n>` (or `-p`) where binding `<bind-interface>:<n>` fails: the port is occupied by another process, `<n>` is a privileged port (<1024) without rights, or `--bind` names an address not present on the machine.
Common situations: A previous `hugo server` (or another dev server) still holding port 1313; two Hugo projects started with the same `-p`; `--bind 0.0.0.0` vs an unavailable interface IP in containers/WSL; choosing port 80/443 without elevation.
Related errors
- unable to find alternative port to use: %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/19d4c96d7a846ec1.json.
Report an issue: GitHub ↗.