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

  1. Retry the command — transient slowness often resolves on a second attempt.
  2. Check the server's stdout.log/stderr.log in the per-host server dir to see if it is crash-looping.
  3. Free system resources or stop competing processes that slow server startup.
  4. 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

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

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/91d085aa6e1c4c80. Report an issue: GitHub.