nats-io/nats-server · error
failed to be ready for connections after %s: startup did not
Error message
failed to be ready for connections after %s: startup did not complete
What it means
When running with `dont_listen` (in-process/server-embedded mode), there is no listener to probe, so ReadyForConnections polls s.startupComplete instead. If startup does not finish within the deadline, the caller gets this timeout error after %s (the waited duration).
Source
Thrown at server/server.go:4017
chk["websocket"] = info{ok: (opts.Websocket.Port == 0 || s.websocket.listener != nil), err: s.websocket.listenerErr}
chk["mqtt"] = info{ok: (opts.MQTT.Port == 0 || s.mqtt.listener != nil), err: s.mqtt.listenerErr}
s.mu.RUnlock()
var numOK int
for _, inf := range chk {
if inf.ok {
numOK++
}
}
if numOK == len(chk) {
// In the case of DontListen option (no accept loop), we still want
// to make sure that Start() has done all the work, so we wait on
// that.
if opts.DontListen {
select {
case <-s.startupComplete:
case <-time.After(d):
return fmt.Errorf("failed to be ready for connections after %s: startup did not complete", d)
}
}
return nil
}
if d > 25*time.Millisecond {
time.Sleep(25 * time.Millisecond)
}
}
failed := make([]string, 0, len(chk))
for name, inf := range chk {
if inf.ok && inf.err != nil {
failed = append(failed, fmt.Sprintf("%s(ok, but %s)", name, inf.err))
}
if !inf.ok && inf.err == nil {
failed = append(failed, name)
}
if !inf.ok && inf.err != nil {View on GitHub (pinned to 3a66a489d2)
Solutions
- Ensure Start() was actually invoked and completes: check logs for startup errors before waiting
- Increase the ReadyForConnections timeout or poll longer in embedded mode
- Fix whatever blocks startup (e.g. resolver URL unreachable) — inspect the wrapped startup logs
- Verify DontListen mode setup: with dont_listen the app must rely on in-process clients only
Example fix
// before
if !s.ReadyForConnections(500 * time.Millisecond) { ... }
// after
if !s.ReadyForConnections(10 * time.Second) {
log.Fatalf("embedded server did not become ready")
} Defensive patterns
Strategy: try-catch
Validate before calling
// In embedded (dont_listen) mode, confirm Start() was called and give a generous deadline
if !started.Flag("started") {
return errors.New("call srv.Start() before ReadyForConnections")
} Try / catch
if !srv.ReadyForConnections(30 * time.Second) {
if opts.DontListen {
log.Printf("startup did not complete within deadline; inspect server logs for blocking startup (resolver, options)")
srv.Shutdown()
return errors.New("embedded server startup timeout")
}
return errors.New("server not ready")
} Prevention
- Always call Start() before ReadyForConnections in embedded mode
- Use a timeout proportional to expected resolver latency (URL resolvers can take seconds)
- Monitor server logs for panics during startup that prevent the completion signal
- In tests, fail fast on !ReadyForConnections instead of hanging on in-process clients
When it happens
Trigger: Calling s.ReadyForConnections(d) (or NewServer+Start in embedded mode) with opts.DontListen true while Start() has not signaled startupComplete within the timeout — e.g. slow option processing, account resolver stalls, or a deadlock in startup.
Common situations: Embedded nats-server in tests/applications where Start() blocks on a slow resolver (URL fetch timeouts) or the caller never called Start(); too-short timeout (e.g. ReadyForConnections(time.Second)) under heavy init; startup goroutine panicking before signaling.
Related errors
- gsl: notification already registered
- error creating store for stream
- error creating store for consumer
- JS_STREAM_OFFLINE
- JS_ERR_GENERIC
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/ee2ae3556309a4d5.
Report an issue: GitHub.