gastownhall/beads · warning · errStartInterrupted
%w for %s: stop epoch advanced during backend start (%v)
Error message
%w for %s: stop epoch advanced during backend start (%v)
What it means
This classified error indicates the database backend's Start(ctx) failed because a concurrent shutdown advanced the proxy's stop epoch while the backend was starting. The library wraps errStartInterrupted ('proxy startup interrupted by concurrent shutdown') so the spawning parent can distinguish 'interrupted by deliberate stop' from a genuine backend boot failure; the original child error is included parenthetically.
Source
Thrown at internal/storage/dbproxy/proxy/server.go:265
}
control, err := startControl(p.rootDir, func() identity.IdentReply {
identMu.RLock()
defer identMu.RUnlock()
return identReply
})
if err != nil {
return fmt.Errorf("start control listener: %w", err)
}
defer func() { _ = control.Close() }()
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)
}View on GitHub (pinned to 71377f2769)
Solutions
- Treat as benign if a shutdown was intentionally requested at that moment - the proxy is stopping anyway
- If unexpected, find what is issuing concurrent Stop/spawn calls (double supervisord, overlapping CLI invocations) and serialize them
- Retry the start once the concurrent shutdown completes; errors.Is(err, errStartInterrupted) identifies this class
- Investigate slow backend startup times if races are frequent
Example fix
// before
if err := p.ListenAndServe(ctx); err != nil {
log.Fatalf("proxy failed: %v", err) // crashes even on intentional shutdown
}
// after
if err := p.ListenAndServe(ctx); err != nil {
if errors.Is(err, proxy.ErrStartInterrupted) {
log.Printf("proxy start aborted by shutdown")
return
}
log.Fatalf("proxy failed: %v", err)
} Defensive patterns
Strategy: try-catch
Try / catch
err := p.ListenAndServe(ctx)
if errors.Is(err, errStartInterrupted) {
// deliberate concurrent shutdown; do not alert or restart
log.Printf("proxy start aborted by concurrent shutdown: %v", err)
return
}
log.Fatalf("proxy start failed: %v", err) Prevention
- Serialize start/stop operations for a given rootDir (single supervisor)
- Use errors.Is with errStartInterrupted to classify intentional interruptions
- Avoid issuing stop commands during backend boot windows
When it happens
Trigger: ListenAndServe -> p.server.Start(ctx) returns an error AND stopEpochChanged reports the stop epoch advanced since the saved p.stopEpoch - i.e. someone called Stop (or a concurrent shutdown path) during backend startup.
Common situations: A user pressing Ctrl-C or a supervisor issuing stop while the proxy was still booting its backend; a competing spawn/shutdown loop in endpoint management racing a slow backend start (e.g. slow disk, large recovery).
Related errors
- errStartInterrupted
- server: ExternalDoltServer.Start: server already started
- ErrStoreClosed
- acquire %s: %w
- check proxy stop epoch after acquiring %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/c3650f265fc5b31a.
Report an issue: GitHub.