{"record":{"id":"c3650f265fc5b31a","repo":"gastownhall/beads","slug":"w-for-s-stop-epoch-advanced-during-backend-star","errorCode":null,"errorMessage":"%w for %s: stop epoch advanced during backend start (%v)","messagePattern":"%w for (.+?): stop epoch advanced during backend start \\((.+?)\\)","errorType":"exception","errorClass":"errStartInterrupted","httpStatus":null,"severity":"warning","filePath":"internal/storage/dbproxy/proxy/server.go","lineNumber":265,"sourceCode":"\t}\n\tcontrol, err := startControl(p.rootDir, func() identity.IdentReply {\n\t\tidentMu.RLock()\n\t\tdefer identMu.RUnlock()\n\t\treturn identReply\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"start control listener: %w\", err)\n\t}\n\tdefer func() { _ = control.Close() }()\n\n\tp.stats.IncBackendStart()\n\tif err := p.server.Start(ctx); err != nil {\n\t\t// Start failed with no backend left running (Start cleans up its own\n\t\t// failure), so there is no teardown to move off the lock; classifying\n\t\t// the epoch-watcher cancellation just keeps the child's exit reason\n\t\t// precise for the spawning parent.\n\t\tif changed, cerr := stopEpochChanged(p.rootDir, p.stopEpoch); cerr == nil && changed {\n\t\t\treturn fmt.Errorf(\"%w for %s: stop epoch advanced during backend start (%v)\", errStartInterrupted, p.rootDir, err)\n\t\t}\n\t\treturn fmt.Errorf(\"start database server: %w\", err)\n\t}\n\n\tif err := waitForServerReady(ctx, p.server, serverReadyTimeout); err != nil {\n\t\tif changed, cerr := stopEpochChanged(p.rootDir, p.stopEpoch); cerr == nil && changed {\n\t\t\treturn abortInterruptedStart()\n\t\t}\n\t\tp.stats.IncBackendStop()\n\t\t_ = stopBackendBounded(p.server)\n\t\treturn fmt.Errorf(\"database server not ready: %w\", err)\n\t}\n\tbirth, err := procid.Capture(os.Getpid())\n\tif err != nil {\n\t\tp.stats.IncBackendStop()\n\t\t_ = stopBackendBounded(p.server)\n\t\treturn fmt.Errorf(\"capture proxy birth identity: %w\", err)\n\t}","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/proxy/server.go#L247-L283","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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"],"exampleFix":"// before\nif err := p.ListenAndServe(ctx); err != nil {\n    log.Fatalf(\"proxy failed: %v\", err) // crashes even on intentional shutdown\n}\n// after\nif err := p.ListenAndServe(ctx); err != nil {\n    if errors.Is(err, proxy.ErrStartInterrupted) {\n        log.Printf(\"proxy start aborted by shutdown\")\n        return\n    }\n    log.Fatalf(\"proxy failed: %v\", err)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := p.ListenAndServe(ctx)\nif errors.Is(err, errStartInterrupted) {\n    // deliberate concurrent shutdown; do not alert or restart\n    log.Printf(\"proxy start aborted by concurrent shutdown: %v\", err)\n    return\n}\nlog.Fatalf(\"proxy start failed: %v\", err)","preventionTips":["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"],"tags":["lifecycle","concurrency","shutdown-race","startup"],"backgroundTag":"proxy-startup-interrupted","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}