gastownhall/beads · critical

backing up corrupt dolt database at %s: %w

Error message

backing up corrupt dolt database at %s: %w

What it means

recoverCorruptManifest wraps os.Rename(dotDolt, backupPath) failures as "backing up corrupt dolt database at %s: %w". When bd detects a corrupt dolt manifest, it moves the entire .dolt directory aside (timestamped .corrupt.backup) before re-initializing; this error means the corrupt database could not be preserved, so recovery aborts rather than destroying data.

Source

Thrown at internal/doltserver/manifest_recovery.go:237

func recoverCorruptManifest(beadsDir, doltDir string) ([]string, error) {
	nomsDirs, err := detectCorruptManifest(beadsDir, doltDir)
	if err != nil {
		return nil, err
	}
	if len(nomsDirs) == 0 {
		return nil, nil
	}

	ts := time.Now().UTC().Format("20060102T150405Z")
	var backups []string
	for _, nomsDir := range nomsDirs {
		dotDolt := filepath.Dir(nomsDir) // .../X/.dolt
		dbDir := filepath.Dir(dotDolt)   // .../X
		backupPath := dotDolt + "." + ts + ".corrupt.backup"

		if err := os.Rename(dotDolt, backupPath); err != nil {
			return backups, fmt.Errorf("backing up corrupt dolt database at %s: %w", dotDolt, err)
		}
		backups = append(backups, backupPath)

		if err := ensureDoltInit(dbDir); err != nil {
			// Best-effort restore so the user is no worse off than before.
			_ = os.RemoveAll(dotDolt)
			_ = os.Rename(backupPath, dotDolt)
			return backups[:len(backups)-1], fmt.Errorf("reinitializing dolt database at %s: %w", dbDir, err)
		}
	}
	return backups, nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Stop all other dolt/bd processes using the workspace (check with lsof +D .dolt or handle.exe), then retry.
  2. Fix ownership/permissions so the bd user can rename the .dolt directory.
  3. Manually back up: cp -r X/.dolt X/.dolt.manual-backup, then remove the corrupt .dolt and let bd re-init.
  4. Check the filesystem/mount health if rename fails with I/O errors.

Example fix

// before (shell)
$ bd start   # fails: backing up corrupt dolt database ...
$ lsof +D myrepo/.dolt        # find the holder
$ kill <pid>                  # stop the stale server
// after
$ bd start   # recovery proceeds: .dolt moved to .dolt.<ts>.corrupt.backup
Defensive patterns

Strategy: validation

Validate before calling

// before attempting recovery, ensure nothing holds .dolt open
out, _ := exec.Command("lsof", "+D", dotDolt).Output()
if len(bytes.TrimSpace(out)) > 0 {
    return fmt.Errorf(".dolt in use; stop other processes first")
}
if info, err := os.Stat(dotDolt); err != nil || !info.IsDir() {
    return fmt.Errorf(".dolt missing or not a directory")
}

Try / catch

backups, err := RecoverCorruptManifest(ws)
if err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && errors.Is(pe.Err, syscall.EBUSY) {
        return fmt.Errorf("another process holds .dolt open; stop it and retry: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: A corrupt manifest signature is detected during server start, recoverCorruptManifest tries to rename the .dolt directory to .dolt.<ts>.corrupt.backup, and the rename fails: files inside are open/locked (another server or process holds them), permission problems, or cross-device paths.

Common situations: A second bd/dolt process is still running against the same workspace holding open file handles (especially on Windows where open files cannot be renamed); bd runs unprivileged while .dolt is root-owned; the workspace is on a network mount with locking issues.

Related errors


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