gastownhall/beads · error

checking dolt metadata directory %s: %w

Error message

checking dolt metadata directory %s: %w

What it means

MarkDoltDirCompatible stats <doltDir>/.dolt to decide whether a local Dolt repository exists before writing the .bd-dolt-ok compatibility marker (internal/doltserver/doltserver.go:1910). A missing .dolt is a no-op success; this error is returned only when os.Stat fails for any other reason — permission denied, I/O error, too many symlinks, etc. The wrapped err is the raw *PathError, so the message includes the exact syscall failure.

Source

Thrown at internal/doltserver/doltserver.go:1910

// 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)
	}
	return nil
}

// ensureDoltInit initializes a dolt database directory if .dolt/ doesn't exist.
// If .dolt/ exists, seeds the .bd-dolt-ok marker for existing working databases.
// See GH#2137 for background on pre-0.56 database compatibility.

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped os.PathError — the syscall (stat) and errno (e.g. permission denied) identify the cause.
  2. Check permissions on the dolt dir and its parents: `ls -ld <doltDir> <doltDir>/.dolt` and each ancestor directory; fix with chmod/chown if bd runs as another user.
  3. If the path is on a network/removable volume, remount it and retry.
  4. If .dolt is a dangling symlink, remove it (`rm <doltDir>/.dolt`) so bd treats the dir as having no repo, then re-initialize.
  5. Run `bd doctor` to diagnose the state of the local dolt directory.

Example fix

// before: bd cannot stat .dolt because a backup tool replaced it with a dangling symlink
$ ls -ld ~/.beads/dolt/.dolt
lrwxr-xr-x 1 me me 20 ... .dolt -> /mnt/backup/.dolt (gone)
// after
$ rm ~/.beads/dolt/.dolt
$ bd doctor   # re-init or repair as advised
Defensive patterns

Strategy: validation

Validate before calling

// Validate the dolt dir is stat-able before invoking bd paths that call MarkDoltDirCompatible
import "os"
func checkDoltDir(doltDir string) error {
    info, err := os.Stat(doltDir)
    if err != nil { return err }
    if !info.IsDir() { return fmt.Errorf("%s is not a directory", doltDir) }
    if d := filepath.Join(doltDir, ".dolt"); doltExists(d) {
        if _, err := os.Stat(d); err != nil { return err } // surfaces permission/EIO early
    }
    return nil
}

Try / catch

// Go: distinguish permission problems from other failures and report the path
if err := MarkDoltDirCompatible(dir); err != nil && strings.HasPrefix(err.Error(), "checking dolt metadata directory") {
    var perr *os.PathError
    if errors.As(err, &perr) && errors.Is(perr.Err, syscall.EACCES) {
        return fmt.Errorf("fix permissions on %s (run as the owning user)", dir)
    }
    return err
}

Prevention

When it happens

Trigger: Calling MarkDoltDirCompatible (directly or via bd server/repair paths) where <doltDir>/.dolt exists but cannot be stat'ed: parent directory lacks execute/search permission, the path traverses an unavailable NFS/network mount, .dolt is a broken symlink chain, or the filesystem returns EIO.

Common situations: Repository on a disconnected network drive; directory permissions changed by a sync/backup tool; .dolt replaced by a dangling symlink; running bd under a different user than the one who owns ~/.beads or the repo's dolt dir.

Related errors


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