gastownhall/beads · error

kill verified orphan backend pid %d from %s: %w

Error message

kill verified orphan backend pid %d from %s: %w

What it means

Cleanup verified the recorded PID as this workspace's orphaned backend and attempted to kill it. This error wraps a failure of handle.Kill() on that process handle — the orphan backend could not be terminated, so the stale record is left un-quarantined and cleanup aborts.

Source

Thrown at internal/storage/dbproxy/proxy/endpoint.go:837

	handle, dead, err := openRecordedProcess(pf)
	if err != nil {
		return unverifiableProcessError(
			"backend cleanup",
			recordPath,
			pf.Pid,
			err,
			unverifiableProcessChecks{},
		)
	}
	if dead {
		if _, err := quarantineRecord(rootDir, server.PIDFileName, time.Now()); err != nil {
			return fmt.Errorf("quarantine dead backend record: %w", err)
		}
		return nil
	}
	if err := handle.Kill(); err != nil {
		_ = handle.Close()
		return fmt.Errorf("kill verified orphan backend pid %d from %s: %w", pf.Pid, recordPath, err)
	}
	// Close before waiting: an open handle on Windows keeps the dead PID
	// allocated, so procid.Verify would keep matching it and the exit wait
	// below would always time out.
	if err := handle.Close(); err != nil {
		return fmt.Errorf("close verified backend process handle for pid %d: %w", pf.Pid, err)
	}
	if err := waitForRecordedProcessExit(pf, backendExitTimeout); err != nil {
		return fmt.Errorf("wait for verified orphan backend pid %d: %w", pf.Pid, err)
	}
	if _, err := quarantineRecord(rootDir, server.PIDFileName, time.Now()); err != nil {
		return fmt.Errorf("quarantine orphan backend record: %w", err)
	}
	return nil
}

type unverifiableProcessChecks struct {
	LiveEstablished bool

View on GitHub (pinned to 71377f2769)

Solutions

  1. Kill the process manually with elevated privileges: kill -9 <pid> (or Stop-Process -Force -Id <pid> on Windows).
  2. Run the cleanup under the same user (or via sudo) that started the backend.
  3. Confirm with ps/tasklist whether the process already exited; if it is gone, quarantine the record manually and retry.
  4. Check container/sandbox policies if signals are being blocked.

Example fix

// before
Error: kill verified orphan backend pid 4242 from /ws/.beads/dbproxy/dolt-backend.pid: operation not permitted
// after
$ sudo kill -9 4242
$ mv /ws/.beads/dbproxy/dolt-backend.pid /ws/.beads/dbproxy/dolt-backend.pid.stale-$(date +%s)
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check you may signal the recorded pid before invoking cleanup:
if proc, err := os.FindProcess(pid); err == nil {
    _ = proc.Signal(syscall.Signal(0)) // EPERM here predicts kill failure
}

Type guard

func canSignal(pid int) bool {
    p, err := os.FindProcess(pid)
    if err != nil { return false }
    return p.Signal(syscall.Signal(0)) == nil
}

Try / catch

if err := cleanupOrphanBackend(rootDir); err != nil && strings.Contains(err.Error(), "kill verified orphan backend pid") {
    // escalate: run cleanup under the backend's owning user or with sudo,
    // or kill -9 <pid> manually, then quarantine the record
}

Prevention

When it happens

Trigger: openRecordedProcess returned a live handle matching pf, handle.Kill() returns an error at internal/storage/dbproxy/proxy/endpoint.go:835-837 (e.g. insufficient privileges, access denied, process already terminating with a handle error).

Common situations: The orphan backend runs as a different user (e.g. started via sudo) so the current user may not signal it; on Windows, access-denied from OpenProcess-protected processes; hardened containers/seccomp blocking signals.

Related errors


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