gastownhall/beads · critical
database server not ready: %w
Error message
database server not ready: %w
What it means
Wraps a failure of waitForServerReady(ctx, p.server, serverReadyTimeout), which polls the freshly started backend until it is accepting work or the timeout expires. On failure (including timeout) the backend is stopped and ListenAndServe returns this error, so the proxy never publishes itself as ready with a dead backend.
Source
Thrown at internal/storage/dbproxy/proxy/server.go:276
p.stats.IncBackendStart()
if err := p.server.Start(ctx); err != nil {
// Start failed with no backend left running (Start cleans up its own
// failure), so there is no teardown to move off the lock; classifying
// the epoch-watcher cancellation just keeps the child's exit reason
// precise for the spawning parent.
if changed, cerr := stopEpochChanged(p.rootDir, p.stopEpoch); cerr == nil && changed {
return fmt.Errorf("%w for %s: stop epoch advanced during backend start (%v)", errStartInterrupted, p.rootDir, err)
}
return fmt.Errorf("start database server: %w", err)
}
if err := waitForServerReady(ctx, p.server, serverReadyTimeout); err != nil {
if changed, cerr := stopEpochChanged(p.rootDir, p.stopEpoch); cerr == nil && changed {
return abortInterruptedStart()
}
p.stats.IncBackendStop()
_ = stopBackendBounded(p.server)
return fmt.Errorf("database server not ready: %w", err)
}
birth, err := procid.Capture(os.Getpid())
if err != nil {
p.stats.IncBackendStop()
_ = stopBackendBounded(p.server)
return fmt.Errorf("capture proxy birth identity: %w", err)
}
rootID, err := identity.RootID(p.rootDir)
if err != nil {
p.stats.IncBackendStop()
_ = stopBackendBounded(p.server)
return fmt.Errorf("resolve proxy root identity: %w", err)
}
upstreamID := p.server.ID(ctx)
identMu.Lock()
identReply.RootID = rootID
identReply.UpstreamID = upstreamID
identReply.PID = os.Getpid()View on GitHub (pinned to 71377f2769)
Solutions
- Unwrap to see if it was a timeout vs health-check error; increase the readiness budget if startup is legitimately slow
- Check backend logs for crash-on-start (missing files, corruption, permissions)
- Verify the context passed to ListenAndServe is not cancelled prematurely by the caller
- Free CPU/disk contention slowing startup (e.g. other backups running concurrently)
Defensive patterns
Strategy: retry
Try / catch
var lastErr error
for i := 0; i < 3; i++ {
lastErr = p.ListenAndServe(ctx)
if lastErr == nil { break }
if strings.Contains(lastErr.Error(), "not ready") && !errors.Is(lastErr, errStartInterrupted) {
time.Sleep(2 * time.Second) // transient slow-start; retry
continue
}
break
}
if lastErr != nil { log.Fatal(lastErr) } Prevention
- Allow generous readiness time on slow storage or large recovery states
- Pass a non-cancelled context to ListenAndServe
- Monitor backend logs for crash loops between readiness checks
When it happens
Trigger: The backend process started but did not become healthy within serverReadyTimeout, or the readiness probe failed because ctx was cancelled or the backend health check kept erroring.
Common situations: Slow disk or large WAL recovery exceeding the readiness timeout; backend crash-looping after start; context cancelled by the caller mid-startup; backend listening on the wrong port so health checks fail.
Related errors
- backend must be set
- errIdleTimeout
- database server not running
- ErrFSCKTimeout
- not using Dolt backend (configured backend %q)
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/3254702c88990587.
Report an issue: GitHub.