{"record":{"id":"91d085aa6e1c4c80","repo":"charmbracelet/crush","slug":"timed-out-waiting-for-server-readiness","errorCode":null,"errorMessage":"timed out waiting for server readiness","messagePattern":"timed out waiting for server readiness","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cmd/root.go","lineNumber":682,"sourceCode":"func waitForServerReady(ctx context.Context, hostURL *url.URL) error {\n\thttpClient, reqURL, err := readinessHTTPClient(hostURL)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconst perAttempt = 100 * time.Millisecond\n\tdeadline := time.Now().Add(serverReadyTimeout())\n\n\tvar lastErr error\n\tfor {\n\t\tif err := ctx.Err(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif time.Now().After(deadline) {\n\t\t\tif lastErr != nil {\n\t\t\t\treturn lastErr\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"timed out waiting for server readiness\")\n\t\t}\n\n\t\tattemptCtx, cancel := context.WithTimeout(ctx, perAttempt)\n\t\terr := probeHealth(attemptCtx, httpClient, reqURL, hostURL)\n\t\tcancel()\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\t\tlastErr = err\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-time.After(perAttempt):\n\t\t}\n\t}\n}\n","sourceCodeStart":664,"sourceCodeEnd":700,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/cmd/root.go#L664-L700","documentation":"waitForServerReady probes the server's health endpoint on a deadline. If every attempt fails and the deadline passes with no lastErr recorded, it returns the sentinel 'timed out waiting for server readiness'. It indicates the spawned or existing server never became healthy in time.","triggerScenarios":"The server takes longer than the deadline to bind and answer /health, probeHealth keeps failing (connection refused, non-2xx), or ctx is honoured but all attempts error without producing a final lastErr by the deadline.","commonSituations":"Cold start under heavy machine load; slow disk delaying server init; server crashing and restarting in a loop; antivirus scanning the binary at each spawn; resource limits (ulimit, cgroup) slowing or blocking the server.","solutions":["Retry the command — transient slowness often resolves on a second attempt.","Check the server's stdout.log/stderr.log in the per-host server dir to see if it is crash-looping.","Free system resources or stop competing processes that slow server startup.","If startup is legitimately slow in your environment, increase the readiness deadline before calling waitForServerReady."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"deadline := time.Now().Add(30 * time.Second)\nfor time.Now().Before(deadline) {\n\tif err := quickHealthProbe(ctx, hostURL); err == nil {\n\t\tbreak\n\t}\n\ttime.Sleep(500 * time.Millisecond)\n}","typeGuard":null,"tryCatchPattern":"ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\nerr := waitForServerReady(ctx, hostURL)\nif err != nil {\n\tif errors.Is(err, context.DeadlineExceeded) || strings.Contains(err.Error(), \"timed out\") {\n\t\t// one clean retry after killing a possibly wedged server\n\t\tos.Remove(socketPath)\n\t\terr = waitForServerReady(ctx, hostURL)\n\t}\n}","preventionTips":["Retry once with a clean socket removal before giving up","Watch machine load; startup probes are sensitive to CPU/disk pressure","Inspect server logs to distinguish slowness from crash-looping","Tune the readiness deadline for known-slow environments"],"tags":["timeout","health-check","server","startup"],"backgroundTag":"server-readiness-timeout","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}