gastownhall/beads · error

kill verified pid %d from %s: %w

Error message

kill verified pid %d from %s: %w

What it means

During proxy.Shutdown, stopAndAcquire verified a recorded PID legitimately belongs to this workspace's proxy/backend and tried to kill it, but the OS kill call (handle.Kill()) failed. The error wraps the underlying syscall error (e.g. permission denied, process gone). Shutdown refuses to continue rather than leaving the lock in an unknown state.

Source

Thrown at internal/storage/dbproxy/proxy/shutdown.go:264

				return nil, unverifiableProcessError(
					"shutdown",
					recordPath,
					pf.Pid,
					openErr,
					unverifiableProcessChecks{},
				)
			}
			if dead {
				if _, quarantineErr := quarantineRecord(rootDir, pidName, time.Now()); quarantineErr != nil {
					lock.Unlock()
					return nil, fmt.Errorf("quarantine dead process record %s: %w", recordPath, quarantineErr)
				}
				return lock, nil
			}
			if killErr := handle.Kill(); killErr != nil {
				_ = handle.Close()
				lock.Unlock()
				return nil, fmt.Errorf("kill verified pid %d from %s: %w", pf.Pid, recordPath, killErr)
			}
			if closeErr := handle.Close(); closeErr != nil {
				lock.Unlock()
				return nil, fmt.Errorf("close verified process handle for pid %d: %w", pf.Pid, closeErr)
			}
			waitBudget := max(time.Until(deadline), shutdownPostKillMinimum)
			if waitErr := waitForRecordedProcessExit(pf, waitBudget); waitErr != nil {
				lock.Unlock()
				return nil, fmt.Errorf("confirm verified pid %d stopped: %w", pf.Pid, waitErr)
			}
			if removeErr := pidfile.Remove(rootDir, pidName); removeErr != nil {
				lock.Unlock()
				return nil, fmt.Errorf("remove stopped process record %s: %w", recordPath, removeErr)
			}
			return lock, nil

		case !lockfile.IsLocked(err):
			return nil, fmt.Errorf("probe %s: %w", lockPath, err)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Run the shutdown command as the same user that started the daemon (check with ps -o user= -p <pid>).
  2. If the process already exited, delete the stale pidfile and lock, then retry bd shutdown.
  3. Check the wrapped %w error: EPERM means permissions, ESRCH means already gone.
  4. Kill the process manually (kill <pid>) and remove the pidfile, then retry.

Example fix

// before
err := proxy.Shutdown(rootDir) // fails: kill verified pid 4321 ...: operation not permitted
// after
// start daemon and shutdown as the same user
$ bd dolt start   # as user 'alice'
$ bd dolt stop    # also as user 'alice'
Defensive patterns

Strategy: try-catch

Validate before calling

pid=$(cat .beads/dolt.pid | head -1); [ "$(ps -o user= -p ${pid#*:} 2>/dev/null | tr -d ' ')" = "$(whoami)" ] && echo ok || echo 'pid owned by another user; run shutdown as that user'

Try / catch

if err := proxy.Shutdown(rootDir); err != nil {
    var uerr *UnverifiableProcessError
    if errors.As(err, &uerr) { /* handle legacy/unverifiable path */ }
    if strings.Contains(err.Error(), "kill verified pid") {
        // advise same-user restart or manual kill + pidfile removal
    }
}

Prevention

When it happens

Trigger: bd Shutdown finds a live, verified pid in the pidfile and handle.Kill() returns an error — typically EPERM because the recorded process runs as a different user, or the process exited between open and kill.

Common situations: The daemon was started under sudo or another account while shutdown runs as the current user; a container/namespace boundary makes the PID invisible or unkillable; a race where the process exits just before the kill.

Related errors


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