gastownhall/beads · error

stop database server: %w

Error message

stop database server: %w

What it means

After the proxy run loop finishes, ListenAndServe attempts a bounded stop of the embedded Dolt backend via stopBackendBounded (s.Stop with backendStopTimeout). If that stop returns an error, it is wrapped as 'stop database server: %w' and joined with any run error via errors.Join. This signals the backend may still be running or was not shut down cleanly within the timeout.

Source

Thrown at internal/storage/dbproxy/proxy/server.go:347

	}
	defer func() { _ = pidfile.Remove(p.rootDir, PIDFileName) }()

	g, gctx := errgroup.WithContext(ctx)
	g.Go(func() error {
		<-gctx.Done()
		_ = p.listener.Close()
		_ = control.Close()
		return nil
	})
	g.Go(func() error { return p.idleWatcher(gctx) })
	g.Go(func() error { return p.acceptLoop(gctx) })

	runErr := g.Wait()
	_ = p.conns.Wait()
	p.stats.IncBackendStop()
	stopErr := stopBackendBounded(p.server)
	if stopErr != nil {
		stopErr = fmt.Errorf("stop database server: %w", stopErr)
	}
	if errors.Is(runErr, errIdleTimeout) || sigReceived.Load() {
		runErr = nil
	}
	return errors.Join(runErr, stopErr)
}

func stopBackendBounded(s server.DatabaseServer) error {
	ctx, cancel := context.WithTimeout(context.Background(), backendStopTimeout)
	defer cancel()
	return s.Stop(ctx)
}

func (p *proxyServer) idleWatcher(ctx context.Context) error {
	if p.idleTimeout <= 0 {
		<-ctx.Done()
		return nil
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Run 'bd dolt stop' again (or proxy.Shutdown) after a short delay — it will verify/quarantine the leftover backend record.
  2. Check for a live dolt backend process (ps aux | grep dolt) and stop or kill it if wedged.
  3. Inspect the wrapped cause after 'stop database server: ' for the concrete Stop failure.
  4. If the backend is genuinely dead, clear stale control files via the proxy's purge path and restart.
  5. Increase headroom on the machine (CPU/IO pressure) if the bounded timeout is routinely exceeded.

Example fix

// before
err := proxy.ListenAndServe(...) // returns: stop database server: context deadline exceeded
// after
if err != nil && strings.Contains(err.Error(), "stop database server") {
    _ = proxy.Shutdown(rootDir) // verify/quarantine leftover records, then retry start
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: confirm the backend record and process state are sane
pf, err := pidfile.Read(rootDir, server.PIDFileName)
if err == nil && pf != nil {
    if alive := processExists(pf.Pid); alive {
        // backend currently running; ensure machine headroom for a bounded stop
    }
}

Try / catch

if err := proxy.ListenAndServe(ctx, ...); err != nil {
    if strings.Contains(err.Error(), "stop database server") {
        // backend may be left running; run proxy.Shutdown to verify/quarantine, then retry
        if sErr := proxy.Shutdown(rootDir); sErr != nil { /* escalate */ }
    }
    return err
}

Prevention

When it happens

Trigger: The proxy is shutting down (idle timeout, signal, or listener error) and backend Stop(ctx) fails or exceeds backendStopTimeout — e.g. the dolt backend process is wedged, already exited unexpectedly, or the stop command times out.

Common situations: Backend hung on a long query or fsync during shutdown; backend killed externally moments before proxy stop; resource exhaustion making the bounded stop time out; SIGKILL'd backend leaving Stop to report failure.

Related errors


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