gastownhall/beads · error

dolt sql-server exited immediately on port %d (attempt %d/%d

Error message

dolt sql-server exited immediately on port %d (attempt %d/%d)

What it means

Start() sleeps 200ms after spawning dolt sql-server and checks isProcessAlive(pid). A process that dies within that window almost always failed to bind its port (bind failure), so Start records 'dolt sql-server exited immediately on port %d (attempt %d/%d)' as lastErr and retries or breaks depending on whether the port was explicit.

Source

Thrown at internal/doltserver/doltserver.go:1452

			// restarted. os/exec does not close those; mark them first.
			sanitizeInheritedFDs()

			if startErr := cmd.Start(); startErr != nil {
				lastErr = startErr
				if !explicitPort {
					continue // retry with a new ephemeral port
				}
				break
			}

			pid = cmd.Process.Pid
			_ = cmd.Process.Release()

			// Quick check: did the process exit immediately (bind failure)?
			// Give it a moment to fail on port bind before proceeding.
			time.Sleep(200 * time.Millisecond)
			if !isProcessAlive(pid) {
				lastErr = fmt.Errorf("dolt sql-server exited immediately on port %d (attempt %d/%d)", actualPort, i+1, attempts)
				pid = 0
				if !explicitPort {
					continue
				}
				break
			}

			lastErr = nil
			break
		}
		_ = logFile.Close()

		if lastErr != nil {
			// GH#3290 / bd-6dnrw.6: unclean-shutdown manifest corruption is
			// detected here but never auto-repaired — reinitializing .dolt is
			// destructive, so repair stays behind explicit bd doctor --fix.
			if dirs, detErr := detectCorruptManifest(beadsDir, doltDir); detErr == nil && len(dirs) > 0 {
				return nil, fmt.Errorf("failed to start dolt server after %d attempts: %w\n"+

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the server log (path printed by the final wrapped error) for the child's actual exit reason.
  2. Free the port: find the holder with ss -ltnp / lsof -i :PORT and stop it, or pick another port.
  3. Run bd doctor --fix if the final error mentions corrupt manifest (GH#3290).
  4. Retry with port 0 (ephemeral) so the OS allocates a fresh port per attempt.

Example fix

// before
BD_PORT=4141 bd start
// error: exited immediately on port 4141
// after: check logs and free the port, or
BD_PORT=0 bd start
Defensive patterns

Strategy: retry

Validate before calling

// check the port is bindable and no orphan dolt is running
const inUse = await new Promise(res => {
  const s = require('net').createServer();
  s.once('error', () => res(true)); s.listen(port, () => { s.close(); res(false); });
});
if (inUse) console.warn(`port ${port} already in use`);

Type guard

null

Try / catch

try {
  await bdStart();
} catch (e) {
  if (/exited immediately on port/.test(e.message)) {
    await checkLogFile();   // find real exit reason
    await killOrphanedDolt();
    await retryWithEphemeralPort();
  }
  throw e;
}

Prevention

When it happens

Trigger: Child dolt sql-server exits before the 200ms aliveness check — usually 'address already in use' bind failure, but also invalid config or data-dir corruption causing instant exit.

Common situations: Another process bound the explicit port between allocation and bind (TOCTOU); orphaned dolt sql-server still holding the port; malformed managed config YAML; corrupt .dolt manifest crashing the server at boot.

Related errors


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