nats-io/nats-server · error
can't listen to the monitor port: %v
Error message
can't listen to the monitor port: %v
What it means
The monitoring listener could not be bound: net.Listen("tcp", host:port) failed and the underlying OS error is wrapped. Typical causes are the port already in use, permission denied for privileged ports, or an unbindable host address.
Source
Thrown at server/server.go:3140
hp = net.JoinHostPort(opts.HTTPHost, strconv.Itoa(port))
config := opts.TLSConfig.Clone()
if !s.ocspPeerVerify {
config.GetConfigForClient = s.getMonitoringTLSConfig
config.ClientAuth = tls.NoClientCert
}
httpListener, err = tls.Listen("tcp", hp, config)
} else {
port = opts.HTTPPort
if port == -1 {
port = 0
}
hp = net.JoinHostPort(opts.HTTPHost, strconv.Itoa(port))
httpListener, err = net.Listen("tcp", hp)
}
if err != nil {
return fmt.Errorf("can't listen to the monitor port: %v", err)
}
rport := httpListener.Addr().(*net.TCPAddr).Port
s.Noticef("Starting %s monitor on %s", monitorProtocol, net.JoinHostPort(opts.HTTPHost, strconv.Itoa(rport)))
mux := http.NewServeMux()
// Root
mux.HandleFunc(s.basePath(RootPath), s.HandleRoot)
// Varz
mux.HandleFunc(s.basePath(VarzPath), s.HandleVarz)
// Connz
mux.HandleFunc(s.basePath(ConnzPath), s.HandleConnz)
// Routez
mux.HandleFunc(s.basePath(RoutezPath), s.HandleRoutez)
// Gatewayz
mux.HandleFunc(s.basePath(GatewayzPath), s.HandleGatewayz)
// LeafzView on GitHub (pinned to 3a66a489d2)
Solutions
- Check and free the port: `lsof -i :8222` / `ss -ltnp`, stop the conflicting process or pick another port
- Bind to 0.0.0.0 or the loopback interface instead of an unresolvable host in `http_host`
- For ports <1024 run with the required capability/root or choose a high port
- Read the wrapped `%v` OS error to distinguish address-in-use vs permission vs no-route
Example fix
// before http_host: "myhost.internal" http_port: 8222 // after http_host: "0.0.0.0" http_port: 8222
Defensive patterns
Strategy: validation
Validate before calling
// Pre-check that the monitor port is bindable before starting the server
func portFree(host string, port int) error {
ln, err := net.Listen("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
if err != nil { return err }
return ln.Close()
} Try / catch
if err := srv.StartMonitoring(); err != nil {
var wrapped string = err.Error()
if strings.Contains(wrapped, "can't listen to the monitor port") {
if strings.Contains(wrapped, "address already in use") {
log.Print("monitor port taken: stop the other process or change http_port")
} else if strings.Contains(wrapped, "permission denied") {
log.Print("use a port >1024 or grant CAP_NET_BIND_SERVICE")
}
}
return err
} Prevention
- Prefer high ports (>1024) for monitoring to avoid permission issues
- Use http_host: 0.0.0.0 or a concrete local IP, not an external hostname
- Check for lingering instances with `ss -ltnp | grep 8222` before restarts
- In containers, ensure the port isn't claimed by a sidecar or previous run
When it happens
Trigger: startMonitoring calls net.Listen for opts.HTTPPort/HTTPSPort (or the randomly allocated port) on opts.HTTPHost; any listen error (EADDRINUSE, EACCES, invalid host) triggers this.
Common situations: Another nats-server or old instance still holding 8222; binding to a hostname that doesn't resolve to a local interface; port <1024 without root; container missing CAP_NET_BIND_SERVICE.
Related errors
- could not fetch <%q>: %v
- can't specify both HTTP (%v) and HTTPs (%v) ports
- TLS cert and key required for HTTPS
- fetching jwt failed due to shutdown
- fetching jwt timed out
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/73d8a4b8fabfabdd.
Report an issue: GitHub.