gastownhall/beads · error

failed to start dolt server after %d attempts: %w Check logs

Error message

failed to start dolt server after %d attempts: %w
Check logs: %s

What it means

The generic failure path when all dolt sql-server start attempts are exhausted and no corrupt manifest was detected. It wraps the last attempt's error (lastErr) and points at the server log file. This is what users see when the specific GH#3290 corruption branch does not apply.

Source

Thrown at internal/doltserver/doltserver.go:1475

				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"+
					"Corrupt manifest with no recoverable data detected (GH#3290) in:\n  %s\n"+
					"Run 'bd doctor --fix' to back up the corrupt database(s) and reinitialize.\nCheck logs: %s",
					attempts, lastErr, strings.Join(dirs, "\n  "), logPath(beadsDir))
			}
			return nil, fmt.Errorf("failed to start dolt server after %d attempts: %w\nCheck logs: %s",
				attempts, lastErr, logPath(beadsDir))
		}
	}

	// Write PID and port files
	if err := os.WriteFile(pidPath(beadsDir), []byte(strconv.Itoa(pid)), 0600); err != nil {
		if proc, findErr := os.FindProcess(pid); findErr == nil {
			_ = proc.Kill()
		}
		return nil, fmt.Errorf("writing PID file: %w", err)
	}
	if err := writePortFile(beadsDir, actualPort); err != nil {
		if proc, findErr := os.FindProcess(pid); findErr == nil {
			_ = proc.Kill()
		}
		_ = os.Remove(pidPath(beadsDir))
		return nil, fmt.Errorf("writing port file: %w", err)
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the referenced log file (last line of the error) for the child's real failure.
  2. Resolve the underlying issue from lastErr: free the port, fix config, or verify the dolt binary runs (dolt version).
  3. Try an ephemeral port (port 0) to rule out port conflicts.
  4. Check system resources: ulimits, memory, and that the host address is valid on this machine.

Example fix

// before: bind to a nonexistent host IP
BD_HOST=10.0.0.99 bd start  # attempts exhausted
// after
BD_HOST=127.0.0.1 bd start   # or unset to use default
Defensive patterns

Strategy: try-catch

Validate before calling

// sanity checks before starting
await fs.access(path.join(dataDir, '.dolt'), fs.constants.W_OK);
await execFile('dolt', ['version']); // dolt binary works
const hostIfaces = Object.keys(os.networkInterfaces());
if (cfgHost && !hostIfaces.includes(cfgHost) && cfgHost !== 'localhost' && cfgHost !== '127.0.0.1')
  console.warn('configured host not present on this machine');

Type guard

null

Try / catch

try {
  await bdStart();
} catch (e) {
  const m = /failed to start dolt server after (\d+) attempts/.exec(e.message);
  if (m && !/Corrupt manifest/.test(e.message)) {
    const logTail = await readTail(logFile); // log path is in the error
    // act on logTail: port conflict, bad config, resource limits
  }
  throw e;
}

Prevention

When it happens

Trigger: Every attempt failed (bind conflicts, immediate exits, config issues) and detectCorruptManifest found nothing — e.g. port held by a foreign process across all retries.

Common situations: Persistent port conflict; repeated spawn failures due to a broken dolt binary or PATH; resource limits (fork failures); misconfigured host binding (e.g. bad interface address).

Related errors


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