gastownhall/beads · error

proxy.ForceStopUnverified: record has a verifiable v2 worksp

Error message

proxy.ForceStopUnverified: record has a verifiable v2 workspace identity; use proxy.Shutdown

What it means

requireUnverifiableRecord refuses to force-stop a pidfile record whose RootID matches the current workspace. Such a record has a verifiable v2 workspace identity, meaning the safe proxy.Shutdown path should be used instead of the destructive force-stop path. ForceStopUnverified is deliberately restricted to records whose ownership cannot be verified.

Source

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

		return nil, nil
	}
	report.RecordFound = true
	report.PID = record.Pid
	return record, nil
}

func requireUnverifiableRecord(rootDir string, record *pidfile.PidFile, wantKind string) error {
	if err := record.ValidateV2(wantKind); err != nil {
		return nil
	}
	rootID, err := identity.RootID(rootDir)
	if err != nil {
		// Failing open here would route a possibly-verifiable record into the
		// destructive force path; surface the identity failure instead.
		return fmt.Errorf("proxy.ForceStopUnverified: resolve workspace identity: %w", err)
	}
	if record.RootID == rootID {
		return errors.New(
			"proxy.ForceStopUnverified: record has a verifiable v2 workspace identity; use proxy.Shutdown",
		)
	}
	return nil
}

func inspectAndStopUnverifiedPID(rootDir string, pid int, deadline time.Time, report *ForceStopReport) error {
	if pid <= 0 {
		return fmt.Errorf("proxy.ForceStopUnverified: record %s has invalid pid %d", report.RecordPath, pid)
	}
	// One stable handle covers inspection and signaling, so the PID cannot be
	// recycled between the executable check and the kill on platforms with a
	// pinning primitive (Linux pidfd, Windows process handle).
	proc, gone, err := openUnverifiedProcess(pid)
	if err != nil {
		return fmt.Errorf("proxy.ForceStopUnverified: open pid %d: %w", pid, err)
	}
	if gone {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Call proxy.Shutdown instead of ForceStopUnverified for records with a verifiable identity
  2. Verify you are targeting the correct rootDir (the error means this workspace owns the record)
  3. If the record is truly stale, remove the identity mismatch or delete the pidfile manually after confirming the process

Example fix

// before
_, err := proxy.ForceStopUnverified(root) // record owned by this workspace
// after
report, err := proxy.Shutdown(ctx, root) // safe, verified path
Defensive patterns

Strategy: try-catch

Validate before calling

if record.RootID == currentWorkspaceRootID() {
    // record is verifiable — use Shutdown, not ForceStopUnverified
    return proxy.Shutdown(ctx, root)
}

Try / catch

if _, err := proxy.ForceStopUnverified(root); err != nil {
    if strings.Contains(err.Error(), "verifiable v2 workspace identity") {
        _, err = proxy.Shutdown(ctx, root)
    }
    return err
}

Prevention

When it happens

Trigger: Calling proxy.ForceStopUnverified on a rootDir whose pidfile record was written by the current workspace (record.RootID == resolved rootID).

Common situations: Misunderstanding the API split: using ForceStopUnverified for normal restarts instead of Shutdown; workspace identity files regenerated or moved so RootID unexpectedly matches.

Related errors


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