gastownhall/beads · error
%w The Dolt database is locked.%s Try: bd doctor --fix (cle
Error message
%w The Dolt database is locked.%s Try: bd doctor --fix (clears stale locks), or kill the holding process.
What it means
wrapLockError detects that a database error was caused by the Dolt database being locked and augments it with an actionable message: the original error, an optional hint identifying the holding process, and the recommended remediation (bd doctor --fix to clear stale locks, or kill the holder).
Source
Thrown at internal/storage/dolt/store.go:702
func isLockError(err error) bool {
if err == nil {
return false
}
errStr := strings.ToLower(err.Error())
return strings.Contains(errStr, "database is locked") ||
strings.Contains(errStr, "lock file") ||
strings.Contains(errStr, "noms lock") ||
strings.Contains(errStr, "locked by another dolt process")
}
// wrapLockError wraps lock-related errors with actionable guidance.
// Non-lock errors and nil are returned unchanged.
func wrapLockError(err error) error {
if !isLockError(err) {
return err
}
hint := lockProcessHint()
return fmt.Errorf("%w\n\nThe Dolt database is locked.%s\n"+
"Try: bd doctor --fix (clears stale locks), or kill the holding process.", err, hint)
}
// lockProcessHint tries to identify the process holding the database lock.
// Returns a hint string like " Process 12345 (bd) may be holding the lock."
// Returns empty string if identification fails or on unsupported platforms.
func lockProcessHint() string {
// Look for other bd/dolt processes that might hold the lock
entries, err := os.ReadDir("/proc")
if err != nil {
// /proc not available (macOS, Windows, FreeBSD) — skip PID detection
return ""
}
myPID := os.Getpid()
var holders []string
for _, entry := range entries {
if !entry.IsDir() {View on GitHub (pinned to 71377f2769)
Solutions
- Run bd doctor --fix to clear stale Dolt locks.
- Identify and terminate the holding process (see the 'Process NNNN' hint appended to the error).
- Avoid running multiple bd processes against the same database concurrently; retry after the other finishes.
Example fix
// before $ bd update bd-1 --status closed # fails: database is locked // after $ bd doctor --fix $ bd update bd-1 --status closed
Defensive patterns
Strategy: retry
Validate before calling
// check for a stale Dolt lock before writing
if _, err := os.Stat(filepath.Join(repoPath, ".dolt", "locks")); err == nil {
// entries present: another process may hold the lock
} Type guard
func isLockError(err error) bool {
return err != nil && strings.Contains(strings.ToLower(err.Error()), "lock")
} Try / catch
if err := store.SlotClear(ctx, id, key, actor); err != nil {
if isLockError(err) {
// hint: run bd doctor --fix, or kill the holding process, then retry
}
return err
} Prevention
- Serialize bd commands against the same repo; avoid parallel bd processes.
- Terminate bd processes gracefully so lock files are released.
- After a crash, run bd doctor --fix before the next write.
- Watch for the 'Process NNNN' hint in the message to find the holder.
When it happens
Trigger: Any SQL operation while another process (or a crashed prior process' leftover lock file) holds the Dolt database lock — concurrent bd commands, an editor session, or a stale .lock file after a crash.
Common situations: Running two bd commands simultaneously on the same repo; a previous bd process was SIGKILLed leaving stale locks; a background sync/daemon holds the lock during your command.
Related errors
- %w (lock release also failed: %w)
- schema: acquire migration lock: %w: %w
- schema: acquire migration lock: %w: returned NULL
- schema: acquire migration lock: %w: timeout
- schema: release migration lock: %w: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/d43de824205bc28b.
Report an issue: GitHub.