gastownhall/beads · error
probe backend lock %s: %w
Error message
probe backend lock %s: %w
What it means
cleanupOrphanBackend wraps unexpected errors from util.TryLock on the backend child lock file. This is neither success nor a clean 'locked' answer, so the probe itself failed and backend cleanup cannot safely proceed.
Source
Thrown at internal/storage/dbproxy/proxy/endpoint.go:766
recordPath := pidfile.Path(rootDir, server.PIDFileName)
pf, readErr := pidfile.Read(rootDir, server.PIDFileName)
childLockPath := filepath.Join(rootDir, server.LockFileName)
childLock, lockErr := util.TryLock(childLockPath)
switch {
case lockErr == nil:
childLock.Unlock()
case lockfile.IsLocked(lockErr):
pid := 0
if pf != nil {
pid = pf.Pid
}
return fmt.Errorf(
"refusing backend cleanup: %s is held while proxy lock is free (recorded pid %d at %s); stop the process holding the child lock or remove the stale lock owner before retrying",
childLockPath, pid, recordPath,
)
default:
return fmt.Errorf("probe backend lock %s: %w", childLockPath, lockErr)
}
if readErr != nil {
if isMalformedPIDFileError(readErr) {
return unverifiableProcessError(
"backend cleanup",
recordPath,
0,
readErr,
unverifiableProcessChecks{},
)
}
return fmt.Errorf("read backend record %s: %w", recordPath, readErr)
}
if pf == nil {
return nil
}
if err := pf.ValidateV2(pidfile.KindDoltBackend); err != nil {View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped OS error (errors.Unwrap) — it names the failing syscall on the lock path
- Fix permissions/ownership of the lock file and its directory (chown/chmod, remove a root-owned server.lock if appropriate)
- Verify the workspace is on a filesystem supporting flock (avoid NFS without local locking; move workspace to local disk)
- Confirm the lock path is a regular file (rm a wrongly-typed directory entry named like the lock) and re-run
Example fix
// before
childLock, lockErr := util.TryLock(childLockPath)
...
default:
return fmt.Errorf("probe backend lock %s: %w", childLockPath, lockErr)
// after (caller)
if err := cleanupOrphanBackend(root); err != nil && strings.HasPrefix(err.Error(), "probe backend lock") {
st, statErr := os.Stat(childLockPath)
fmt.Printf("lock probe failed: %v (path stat: %v, %v)\n", err, statErr, st)
} Defensive patterns
Strategy: validation
Validate before calling
lp := root + "/.beads/server.lock"
if fi, err := os.Stat(lp); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("lock path unusable: %w", err)
}
} else if !fi.Mode().IsRegular() {
return fmt.Errorf("%s is not a regular file", lp)
}
if f, err := os.OpenFile(lp, os.O_RDWR|os.O_CREATE, 0o600); err != nil {
return fmt.Errorf("cannot open lock file: %w", err)
} else { f.Close() } Try / catch
err := cleanupOrphanBackend(root)
if err != nil && strings.HasPrefix(err.Error(), "probe backend lock ") {
// wrapped OS error names the failing syscall: fix perms/filesystem, then retry
} Prevention
- Keep the workspace on a local filesystem with working flock (not bare NFS)
- Maintain consistent ownership/permissions on .beads across all bd users
- Ensure lock files are regular files, not directories or symlinks
- Check disk and mount health when lock acquisition starts failing
When it happens
Trigger: util.TryLock(childLockPath) returns an OS error other than EWOULDBLOCK-style 'is locked' — e.g. permission denied opening/creating the lock file, or path errors (component is not a directory, I/O error on the workspace).
Common situations: The lock file path exists as a directory or is otherwise unwritable; workspace mounted read-only or on a filesystem without flock support (some network FS); permission mismatch after running bd as different users (root-owned lock file).
Related errors
- dolt path is not executable
- failed to create backup directory: %w
- failed to create temp file: %w
- create beads directory: %w
- write metadata.json: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/934c1ecd2fa682b9.
Report an issue: GitHub.