gastownhall/beads · error
proxy.ForceStopUnverified: timeout acquiring %s after signal
Error message
proxy.ForceStopUnverified: timeout acquiring %s after signaling
What it means
This error is returned by acquireForceStopLock when, after signaling the unverified PID, the workspace lock stays continuously held by another process until the ForceStopUnverified deadline expires. The lock never became free within the timeout, so quarantine of the pidfile record was abandoned. This is contention, not a filesystem failure (that would be the 'acquire %s: %w' error).
Source
Thrown at internal/storage/dbproxy/proxy/force_stop.go:297
func normalizeForceStopExecutable(name string) string {
name = strings.TrimSpace(filepath.Base(name))
name = strings.TrimSuffix(name, " (deleted)")
name = strings.TrimSuffix(strings.ToLower(name), ".exe")
return name
}
func acquireForceStopLock(lockPath string, deadline time.Time) (*util.Lock, error) {
for {
lock, err := util.TryLock(lockPath)
if err == nil {
return lock, nil
}
if !lockfile.IsLocked(err) {
return nil, fmt.Errorf("proxy.ForceStopUnverified: acquire %s: %w", lockPath, err)
}
if time.Now().After(deadline) {
return nil, fmt.Errorf("proxy.ForceStopUnverified: timeout acquiring %s after signaling", lockPath)
}
time.Sleep(shutdownConfirmPoll)
}
}
func quarantineForceStopRecord(
rootDir string,
pidName string,
record *pidfile.PidFile,
report *ForceStopReport,
) error {
current, err := pidfile.Read(rootDir, pidName)
if err != nil {
return fmt.Errorf("proxy.ForceStopUnverified: re-read %s: %w", report.RecordPath, err)
}
if current == nil {
return nil
}View on GitHub (pinned to 71377f2769)
Solutions
- Identify the lock holder (fuser/lsof on the lock file, or ps for other bd/dolt processes) and stop it, then re-run `bd dolt stop --force`
- Increase ForceStopOptions.Timeout if the holder is expected to release the lock soon (e.g. a finishing bd command)
- If the lock is stale (holder is dead but lock persists, e.g. on NFS), remove the stale lock file only after confirming no live holder, then retry
- Manually quarantine the record (rename proxy.pid to proxy.pid.stale-<unix-timestamp>) once you have confirmed the recorded process is gone
Defensive patterns
Strategy: retry
Validate before calling
// Detect a live lock holder before calling force-stop: // fuser <rootDir>/proxy.lock (or lsof <rootDir>/proxy.lock) — non-empty output means someone holds it
Try / catch
report, err := proxy.ForceStopUnverified(rootDir, proxy.ForceStopOptions{Timeout: 60 * time.Second})
if err != nil && strings.Contains(err.Error(), "timeout acquiring") {
// A holder kept the lock past the deadline: find and stop it, then retry
// fuser -k <rootDir>/proxy.lock (only if the holder is confirmed to be yours)
} Prevention
- Avoid running concurrent `bd dolt stop --force` invocations against the same workspace
- Identify and gracefully stop other bd/dolt processes (bd doctor, running bd commands) before force-stopping
- Increase ForceStopOptions.Timeout when a legitimate lock holder is expected to finish soon
- On NFS, verify lock auto-release works; manually remove stale lock files only after confirming the holder is dead
When it happens
Trigger: Call ForceStopUnverified (`bd dolt stop --force`) on a record whose lock was held (LockWasHeld=true); the PID was signaled, but the external lock holder (another bd/dolt process or stale lock) keeps the lock through every TryLock retry until deadline, so the post-signal acquire times out.
Common situations: Another long-running bd or dolt process legitimately holds the lock and ignores the killed record's PID; a stale lock left by a crashed process whose lockfile implementation does not auto-release (e.g. NFS without proper flock support); concurrent `bd dolt stop --force` invocations from multiple terminals racing each other.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- proxy.ForceStopUnverified: timeout waiting for pid %d to exi
- proxy.ForceStopUnverified: acquire %s: %w
- proxy.ForceStopUnverified: record has a verifiable v2 worksp
- ErrLockHeld
- errIdleTimeout
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/5235c24cc024f339.
Report an issue: GitHub.