{"record":{"id":"3254702c88990587","repo":"gastownhall/beads","slug":"database-server-not-ready-w","errorCode":null,"errorMessage":"database server not ready: %w","messagePattern":"database server not ready: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/storage/dbproxy/proxy/server.go","lineNumber":276,"sourceCode":"\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}\n\trootID, err := identity.RootID(p.rootDir)\n\tif err != nil {\n\t\tp.stats.IncBackendStop()\n\t\t_ = stopBackendBounded(p.server)\n\t\treturn fmt.Errorf(\"resolve proxy root identity: %w\", err)\n\t}\n\tupstreamID := p.server.ID(ctx)\n\tidentMu.Lock()\n\tidentReply.RootID = rootID\n\tidentReply.UpstreamID = upstreamID\n\tidentReply.PID = os.Getpid()","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/proxy/server.go#L258-L294","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var lastErr error\nfor i := 0; i < 3; i++ {\n    lastErr = p.ListenAndServe(ctx)\n    if lastErr == nil { break }\n    if strings.Contains(lastErr.Error(), \"not ready\") && !errors.Is(lastErr, errStartInterrupted) {\n        time.Sleep(2 * time.Second) // transient slow-start; retry\n        continue\n    }\n    break\n}\nif lastErr != nil { log.Fatal(lastErr) }","preventionTips":["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"],"tags":["backend","readiness","timeout","health-check"],"backgroundTag":"backend-not-ready-timeout","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}