gastownhall/beads · critical

start database server: %w

Error message

start database server: %w

What it means

Wraps a genuine failure from p.server.Start(ctx) - the database backend process failed to boot - when the stop epoch has NOT advanced, so it cannot be blamed on concurrent shutdown. The underlying cause (exec failure, config error, database open error) is preserved via %w.

Source

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

		identMu.RLock()
		defer identMu.RUnlock()
		return identReply
	})
	if err != nil {
		return fmt.Errorf("start control listener: %w", err)
	}
	defer func() { _ = control.Close() }()

	p.stats.IncBackendStart()
	if err := p.server.Start(ctx); err != nil {
		// Start failed with no backend left running (Start cleans up its own
		// failure), so there is no teardown to move off the lock; classifying
		// the epoch-watcher cancellation just keeps the child's exit reason
		// precise for the spawning parent.
		if changed, cerr := stopEpochChanged(p.rootDir, p.stopEpoch); cerr == nil && changed {
			return fmt.Errorf("%w for %s: stop epoch advanced during backend start (%v)", errStartInterrupted, p.rootDir, err)
		}
		return fmt.Errorf("start database server: %w", err)
	}

	if err := waitForServerReady(ctx, p.server, serverReadyTimeout); err != nil {
		if changed, cerr := stopEpochChanged(p.rootDir, p.stopEpoch); cerr == nil && changed {
			return abortInterruptedStart()
		}
		p.stats.IncBackendStop()
		_ = stopBackendBounded(p.server)
		return fmt.Errorf("database server not ready: %w", err)
	}
	birth, err := procid.Capture(os.Getpid())
	if err != nil {
		p.stats.IncBackendStop()
		_ = stopBackendBounded(p.server)
		return fmt.Errorf("capture proxy birth identity: %w", err)
	}
	rootID, err := identity.RootID(p.rootDir)
	if err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Unwrap the error (errors.Unwrap / %v shows the child cause) and fix the reported backend problem
  2. Verify the database server binary exists and is executable with the expected version
  3. Check backend logs and database file integrity in rootDir
  4. Ensure adequate resources (fd limits, memory) for the backend process

Example fix

// before
err := p.ListenAndServe(ctx)
log.Println(err) // "start database server: exec: no such file"
// after
if err := p.ListenAndServe(ctx); err != nil {
    var pathErr *exec.Error
    if errors.As(err, &pathErr) {
        log.Fatalf("backend binary missing: %v", pathErr)
    }
    log.Fatal(err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before start, sanity-check the backend prerequisites
if _, err := os.Stat(serverBinary); err != nil {
    return fmt.Errorf("backend binary missing: %w", err)
}
if err := os.Chmod(serverBinary, 0o755); err != nil { return err }

Try / catch

err := p.ListenAndServe(ctx)
if err != nil && !errors.Is(err, errStartInterrupted) {
    log.Fatalf("backend failed to start: %v", err) // %v reveals the wrapped child cause
}

Prevention

When it happens

Trigger: ListenAndServe -> p.server.Start(ctx) returns an error and stopEpochChanged reports no change: the backend itself failed to start (bad dsn, missing binary, corrupt database, port conflicts on the backend).

Common situations: Database binary missing or wrong version after upgrade; corrupt or locked database files in rootDir; insufficient memory/file descriptors; invalid server configuration; backend's own listener port already taken.

Related errors


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