gastownhall/beads · error

resolving .doltcfg directory: %w

Error message

resolving .doltcfg directory: %w

What it means

Start() wraps failures from resolveCfgDir(), which locates or creates the .doltcfg directory the managed dolt sql-server will use. When useArchiveLevelConfig is set, Start resolves the config dir before spawning the server; any filesystem-level failure there is wrapped as 'resolving .doltcfg directory'. The design avoids silently retrying into a fresh unintended $data_dir/.doltcfg when an existing one is unusable.

Source

Thrown at internal/doltserver/doltserver.go:1340

		// Ensure dolt database directory is initialized
		if err := ensureDoltInit(doltDir); err != nil {
			return nil, fmt.Errorf("initializing dolt database: %w", err)
		}

		// Rotate the log if it has grown past the configured ceiling. This is a
		// startup-only check — dolt owns the fd directly once launched, so we can
		// only intervene between runs. See logrotate.go for the caveat discussion.
		maybeRotateLog(beadsDir)

		// Resolve .doltcfg once, before the port retry loop — it does not
		// depend on the port, and an ambiguous both-exist result must fail
		// Start() outright rather than retry into a fresh unintended
		// $data_dir/.doltcfg (see resolveCfgDir).
		var cfgDir string
		if useArchiveLevelConfig {
			cfgDir, err = resolveCfgDir(doltDir)
			if err != nil {
				return nil, fmt.Errorf("resolving .doltcfg directory: %w", err)
			}
		}

		// Open log file
		logFile, err := os.OpenFile(logPath(beadsDir), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600) //nolint:gosec // G304: logPath derives from user-configured beadsDir
		if err != nil {
			return nil, fmt.Errorf("opening log file: %w", err)
		}

		// Resolve the port to use. Explicit ports (env/config) go through
		// reclaimPort for conflict detection. Port 0 means ephemeral — allocate
		// a fresh port from the OS with retry for TOCTOU races.
		actualPort = cfg.Port
		explicitPort := actualPort > 0

		if explicitPort {
			// Explicit port: check for conflicts and adopt existing servers.
			adoptPID, reclaimErr := reclaimPort(cfg.Host, actualPort, beadsDir)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check permissions on the .doltcfg directory inside the data dir and correct ownership (chown -R $USER).
  2. Verify the beads data directory exists, is writable, and is on a writable filesystem (not read-only mount).
  3. Free disk space if the filesystem is full.
  4. Set an explicit, valid beadsDir via env/config and retry bd.

Example fix

// before: data dir owned by root, bd runs as user
$ bd start
// error: resolving .doltcfg directory: mkdir ...: permission denied
// after
$ sudo chown -R "$USER" ~/.beads
$ bd start
Defensive patterns

Strategy: validation

Validate before calling

// before starting
const dataDir = process.env.BD_DIR || path.join(os.homedir(), '.beads');
const cfgDir = path.join(dataDir, '.doltcfg');
await fs.mkdir(cfgDir, { recursive: true });
await fs.access(cfgDir, fs.constants.W_OK); // throws early if unwritable

Type guard

null

Try / catch

try {
  await bdStart();
} catch (e) {
  if (/resolving \.doltcfg directory/.test(e.message)) {
    console.error('Fix permissions on', dataDir, ':', e.cause);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling Start (via EnsureRunningDetailed) with archive-level config enabled when resolveCfgDir cannot resolve doltDir: the path cannot be created (permissions, read-only fs) or stat fails on an existing .doltcfg.

Common situations: Beads dir owned by root after running with sudo; read-only or full disk; NFS/network mount with permission issues; misconfigured beadsDir pointing at an unwritable path.

Related errors


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