charmbracelet/crush · error
timed out waiting for server readiness
Error message
timed out waiting for server readiness
What it means
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.
Source
Thrown at internal/cmd/root.go:682
func waitForServerReady(ctx context.Context, hostURL *url.URL) error {
httpClient, reqURL, err := readinessHTTPClient(hostURL)
if err != nil {
return err
}
const perAttempt = 100 * time.Millisecond
deadline := time.Now().Add(serverReadyTimeout())
var lastErr error
for {
if err := ctx.Err(); err != nil {
return err
}
if time.Now().After(deadline) {
if lastErr != nil {
return lastErr
}
return fmt.Errorf("timed out waiting for server readiness")
}
attemptCtx, cancel := context.WithTimeout(ctx, perAttempt)
err := probeHealth(attemptCtx, httpClient, reqURL, hostURL)
cancel()
if err == nil {
return nil
}
lastErr = err
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(perAttempt):
}
}
}
View on GitHub (pinned to 7944b8e522)
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.
Defensive patterns
Strategy: retry
Validate before calling
deadline := time.Now().Add(30 * time.Second)
for time.Now().Before(deadline) {
if err := quickHealthProbe(ctx, hostURL); err == nil {
break
}
time.Sleep(500 * time.Millisecond)
} Try / catch
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := waitForServerReady(ctx, hostURL)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) || strings.Contains(err.Error(), "timed out") {
// one clean retry after killing a possibly wedged server
os.Remove(socketPath)
err = waitForServerReady(ctx, hostURL)
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- failed to initialize crush server: %v
- server health check failed: %s
- timeout waiting for agent: %w
- timeout waiting for agent readiness
- coder agent not configured
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/91d085aa6e1c4c80.
Report an issue: GitHub.