gastownhall/beads · error

timeout after %s waiting for server at %s

Error message

timeout after %s waiting for server at %s

What it means

waitForReady returns this error when it exhausts its polling deadline without ever observing a MySQL handshake greeting from the server at host:port. It probes with ProbeSQLServer every 500ms until the timeout; a TCP connect that succeeds without a greeting is explicitly not treated as ready. In Start this error is wrapped into the richer 'server started (PID %d) but not accepting connections' messages, but it can also surface directly wherever waitForReady is used.

Source

Thrown at internal/doltserver/doltserver.go:1856

// dolt sql-server process from interpreting probe closes as aborted MySQL
// handshakes and crashing (see gastownhall/beads#4132, #4133).
//
// A dial that succeeds but never greets (TCP listener accepting, MySQL
// engine not yet writing) is not treated as ready: this function keeps
// polling until either a greeting arrives or the deadline is reached.
func waitForReady(host string, port int, timeout time.Duration) error {
	addr := net.JoinHostPort(host, strconv.Itoa(port))
	deadline := time.Now().Add(timeout)

	for time.Now().Before(deadline) {
		greeted, err := ProbeSQLServer("tcp", addr, 500*time.Millisecond) //nolint:gosec // G704: addr is built from internal host+port, not user input
		if err == nil && greeted {
			return nil
		}
		time.Sleep(500 * time.Millisecond)
	}

	return fmt.Errorf("timeout after %s waiting for server at %s", timeout, addr)
}

// ensureDoltIdentity sets dolt global user identity from git config if not already set.
func ensureDoltIdentity() error {
	// Check if dolt identity is already configured
	nameCmd := exec.Command("dolt", "config", "--global", "--get", "user.name")
	if out, err := nameCmd.Output(); err == nil && strings.TrimSpace(string(out)) != "" {
		return nil // Already configured
	}

	// Try to get identity from git
	gitName := "beads"
	gitEmail := "beads@localhost"

	if out, err := exec.Command("git", "config", "user.name").Output(); err == nil {
		if name := strings.TrimSpace(string(out)); name != "" {
			gitName = name
		}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the server log (.beads/dolt-server.log) — a timeout here almost always hides a startup error or a slow init
  2. Allow more time for large databases by increasing the ready timeout (BEADS_DOLT_READY_TIMEOUT) and retrying
  3. If the log shows journal corruption, run 'bd doctor --fix' to back up and reinitialize
  4. Check host resources (memory/CPU/disk I/O) and container limits; free resources or raise limits
  5. Verify the probed host matches the bind host (127.0.0.1 vs 0.0.0.0) and that nothing else grabbed the port

Example fix

// before: huge database, default timeout too short
// error: timeout after 15s waiting for server at 127.0.0.1:41017
// after: extend the readiness window
// $ export BEADS_DOLT_READY_TIMEOUT=120s
// $ bd dolt start
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check: the port must be free and host bindable before waiting for readiness
ln, err := net.Listen("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
if err == nil { ln.Close() } // if bind succeeds here, a later timeout means the server itself is stuck
if err != nil {
    return fmt.Errorf("port %d unavailable on %s", port, host)
}

Try / catch

err := waitForReady(host, port, timeout) // or via doltserver.Start
if err != nil && strings.Contains(err.Error(), "timeout after") {
    // bounded retry: one more start attempt with a larger window
    time.Sleep(2 * time.Second)
    if err := waitForReady(host, port, timeout*2); err != nil {
        return fmt.Errorf("server never became ready at %s; check %s", addr, logPath)
    }
}

Prevention

When it happens

Trigger: The probe loop times out because the dolt sql-server never sends a MySQL handshake: the process is hung during engine init (corrupt journal, huge database), is stuck before binding, or binds but the MySQL layer never starts writing — all before readyTimeout() elapses.

Common situations: Slow first startup on a very large database exceeding the default ready window; corrupt journal after unclean shutdown stalling engine init; resource-starved containers (OOM pressure, throttled CPU); server listening on a different interface than probed; stuck dolt process from a prior crash holding locks.

Understand the failure class

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/221a263e17a39aec. Report an issue: GitHub.