gastownhall/beads · error

server: DoltServer.Start: %w

Error message

server: DoltServer.Start: %w

What it means

Generic wrapper: Start() got past spawning and the pidfile, but waitReady() failed — the dolt sql-server never became dialable within the 30s ready timeout (or its errgroup died, or the caller's ctx was cancelled). The child is stopped, the errgroup drained, and the pidfile removed before returning.

Source

Thrown at internal/storage/dbproxy/server/doltserver.go:314

		_ = cmd.Process.Kill()
		_, _ = cmd.Process.Wait()
		s.eg, s.egCtx, s.cancel, s.pid = nil, nil, nil, 0
		cancel()
		lock.Unlock()
		return fmt.Errorf("server: DoltServer.Start: write pidfile: %w", err)
	}

	eg.Go(func() error {
		defer lock.Unlock()
		return cmd.Wait()
	})

	if err := s.waitReady(ctx); err != nil {
		cancel()
		_ = s.eg.Wait()
		s.eg, s.egCtx, s.cancel, s.pid = nil, nil, nil, 0
		_ = pidfile.Remove(s.rootDir, PIDFileName)
		return fmt.Errorf("server: DoltServer.Start: %w", err)
	}
	return nil
}

func (s *DoltServer) waitReady(ctx context.Context) error {
	deadline := time.Now().Add(startReadyTimeout)
	for {
		if s.egCtx.Err() != nil {
			return errors.New("dolt sql-server exited before listener became ready")
		}

		dctx, dcancel := context.WithTimeout(ctx, startReadyDialTimeout)
		conn, err := s.Dial(dctx)
		dcancel()
		if err == nil {
			_ = conn.Close()
			return nil
		}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the server log file passed to NewDoltServer — dolt's own startup error (bad config, port in use) is written there.
  2. Verify the configured host/port in the dolt server YAML is free: `ss -ltnp | grep <port>`.
  3. Increase readiness headroom by reducing machine load or moving the data dir off slow network storage; ensure Start's ctx is not cancelled early.
  4. Run `dolt sql-server --config <configPath>` manually in rootDir to reproduce and see the startup error directly.

Example fix

// before
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
err := srv.Start(ctx) // ctx cancels before listener is ready
// after
startCtx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
err := srv.Start(startCtx)
Defensive patterns

Strategy: try-catch

Validate before calling

// Sanity-check config and that the configured port is free before Start.
if cfgPort := configuredPort(configPath); cfgPort != 0 {
    ln, err := net.Listen("tcp", fmt.Sprintf("%s:%d", configuredHost(configPath), cfgPort))
    if err != nil {
        return fmt.Errorf("configured port %d unavailable: %w", cfgPort, err)
    }
    ln.Close()
}

Try / catch

if err := srv.Start(ctx); err != nil {
    var detail string
    if strings.Contains(err.Error(), "listener not ready") {
        detail = "dolt did not become ready in time; check server log for child crash"
    } else if strings.Contains(err.Error(), "exited before listener") {
        detail = "dolt crashed at startup; check server log"
    }
    return fmt.Errorf("%s: %w", detail, err)
}

Prevention

When it happens

Trigger: waitReady returns any error: listener never accepts a TCP/socket connection within startReadyTimeout (30s), dolt exited before binding, or the ctx passed to Start() was cancelled. Includes wrapped errors 2406 and the internal "dolt sql-server exited before listener became ready".

Common situations: Slow cold start on loaded machines exceeding 30s; dolt crashing at boot due to bad config (check the log file); port conflicts or host binding misconfiguration; NFS-mounted data dir where the listener comes up late.

Related errors


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