gastownhall/beads · error

dolt directory is required

Error message

dolt directory is required

What it means

MarkDoltDirCompatible writes the .bd-dolt-ok compatibility marker into a Dolt directory and requires a non-empty doltDir path. When called with an empty string it returns "dolt directory is required" immediately, because there is no directory to inspect or mark. The function intentionally no-ops (returns nil) when no .dolt/ directory exists, so the empty-path case is the only hard input validation failure.

Source

Thrown at internal/doltserver/doltserver.go:1903

	if out, err := exec.Command("dolt", "config", "--global", "--add", "user.email", gitEmail).CombinedOutput(); err != nil {
		return fmt.Errorf("setting dolt user.email: %w\n%s", err, out)
	}

	return nil
}

// bdDoltMarker is written after a current bd process creates or acknowledges a
// local Dolt repository. Its absence in an existing .dolt/ directory indicates
// the database was created by a pre-0.56 bd version (which used embedded mode).
// Those databases are incompatible with the current server-only architecture.
const bdDoltMarker = ".bd-dolt-ok"

// MarkDoltDirCompatible writes the canonical bd compatibility marker when
// doltDir contains a local Dolt repository. It no-ops when there is no .dolt/
// directory, which lets server and repair paths call it defensively.
func MarkDoltDirCompatible(doltDir string) error {
	if doltDir == "" {
		return errors.New("dolt directory is required")
	}
	dotDolt := filepath.Join(doltDir, ".dolt")
	if info, err := os.Stat(dotDolt); err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return fmt.Errorf("checking dolt metadata directory %s: %w", dotDolt, err)
	} else if !info.IsDir() {
		return fmt.Errorf("dolt metadata path %s is not a directory", dotDolt)
	}
	markerPath := filepath.Join(doltDir, bdDoltMarker)
	if _, err := os.Stat(markerPath); err == nil {
		return nil
	} else if !os.IsNotExist(err) {
		return fmt.Errorf("checking dolt compatibility marker %s: %w", markerPath, err)
	}
	if err := os.WriteFile(markerPath, []byte("ok\n"), 0600); err != nil {
		return fmt.Errorf("writing dolt compatibility marker %s: %w", markerPath, err)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Fix the caller to pass the resolved bd data directory (ensure config resolution / BEADS_DIR handling populates doltDir before calling)
  2. Initialize the dolt directory first via ensureDoltInit / bd init so a valid path exists
  3. Guard the call site: skip MarkDoltDirCompatible when the path is empty and surface a configuration error instead

Example fix

// before
if err := doltserver.MarkDoltDirCompatible(cfgDir); err != nil { ... }
// after
if cfgDir == "" {
    return fmt.Errorf("bd data directory not configured")
}
if err := doltserver.MarkDoltDirCompatible(cfgDir); err != nil { ... }
Defensive patterns

Strategy: validation

Validate before calling

if doltDir == "" {
    return fmt.Errorf("bd data directory not configured (BEADS_DIR unset?)")
}
if err := doltserver.MarkDoltDirCompatible(doltDir); err != nil {
    return err
}

Try / catch

if err := doltserver.MarkDoltDirCompatible(doltDir); err != nil {
    if strings.Contains(err.Error(), "dolt directory is required") { /* config bug: fix caller */ }
    return fmt.Errorf("mark dolt dir compatible: %w", err)
}

Prevention

When it happens

Trigger: Calling doltserver.MarkDoltDirCompatible("") — e.g. when the configured bd data directory variable was never populated (missing/unset BEADS_DIR or equivalent config resolution returned empty) before server startup or repair paths invoke the marker writer.

Common situations: A config/environment resolution bug yields an empty database dir; calling the repair/defensive marker path in a script or test before any directory is configured; refactoring code that used to pass a hardcoded path to now pass a variable that is empty on first run.

Related errors


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