gastownhall/beads · error

proxy.ForceStopUnverified: acquire %s: %w

Error message

proxy.ForceStopUnverified: acquire %s: %w

What it means

This error is returned by acquireForceStopLock when, after inspecting and signaling the unverified PID, re-attempting to take the workspace lock file fails with an error that is NOT 'lock is held' (lockfile.IsLocked(err) is false). That means TryLock itself failed — e.g. filesystem error creating/opening the lock file, permission problem, or path issue — rather than mere contention. The wrapped cause (%w) carries the underlying reason.

Source

Thrown at internal/storage/dbproxy/proxy/force_stop.go:294

		time.Sleep(shutdownConfirmPoll)
	}
}

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)
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause to identify the filesystem failure (permission denied, ENOENT, EROFS, ENOSPC) and fix the workspace directory state
  2. Restore write permissions on the workspace root: chmod u+w <rootDir> (and its parent) so the lock file can be created
  3. If the workspace was moved/renamed, re-run force-stop from the correct workspace path so lockPath resolves
  4. Confirm the process was actually stopped (ps -p <pid>), then quarantine the record manually (rename proxy.pid to proxy.pid.stale-<unix-timestamp>) to recover without the lock
Defensive patterns

Strategy: validation

Validate before calling

// Verify the workspace is writable and the lock path is creatable before force-stop:
lockPath := filepath.Join(rootDir, "proxy.lock")
if err := os.Chmod(rootDir, 0o755); err != nil { return err }
probe, err := os.OpenFile(lockPath, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil { return err }
probe.Close()

Try / catch

report, err := proxy.ForceStopUnverified(rootDir)
if err != nil {
    var pathErr *os.PathError
    if errors.As(err, &pathErr) {
        // Non-contention lock failure: fix filesystem/permissions at pathErr.Path, then retry
    }
}

Prevention

When it happens

Trigger: Call ForceStopUnverified (`bd dolt stop --force`) on a record whose lock was held by another process (LockWasHeld=true path); after signaling the PID, the retry loop's util.TryLock(lockPath) returns a non-IsLocked error — e.g. read-only filesystem, deleted parent directory, or permission denied on the lock path.

Common situations: Workspace directory made read-only or moved while force-stop runs; another tool deleted/recreated the lock path mid-operation; running under a user without write permission to the workspace root; disk-full conditions preventing lock file creation.

Related errors


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