gastownhall/beads · error
proxy.ForceStopUnverified: resolve workspace identity: %w
Error message
proxy.ForceStopUnverified: resolve workspace identity: %w
What it means
ForceStopUnverified is the destructive path for legacy/unverifiable records only. This error wraps a failure to compute the workspace RootID via identity.RootID(rootDir), which is needed to prove the record is NOT a modern verifiable one. The library deliberately fails closed: it will not route a possibly-verifiable record into the destructive force path.
Source
Thrown at internal/storage/dbproxy/proxy/force_stop.go:179
return nil, fmt.Errorf("proxy.ForceStopUnverified: read %s: %w", report.RecordPath, err)
}
if record == nil {
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 {View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause (%w); restore or regenerate the workspace identity metadata if it is missing/corrupt
- Use proxy.Shutdown instead of ForceStopUnverified if the record actually has a verifiable v2 identity — the follow-on error states this explicitly
- Ensure rootDir is the correct workspace root containing the identity files
- If migrating versions, complete the workspace migration so identity.RootID succeeds before force-stopping
Example fix
// before
report, err := proxy.ForceStopUnverified(rootDir)
// after
if id, idErr := identity.RootID(rootDir); idErr == nil {
_ = id
err = proxy.Shutdown(rootDir) // verifiable workspace: use graceful path
} else {
err = proxy.ForceStopUnverified(rootDir)
} Defensive patterns
Strategy: fallback
Validate before calling
_, idErr := identity.RootID(rootDir) identityResolvable := idErr == nil
Try / catch
report, err := proxy.ForceStopUnverified(rootDir)
if err != nil && strings.Contains(err.Error(), "resolve workspace identity") {
// fail-closed by design; do not force-stop blind. Investigate identity files.
fmt.Fprintf(os.Stderr, "cannot verify record: %v; use graceful shutdown or fix identity\n", err)
return err
} Prevention
- Complete workspace migrations before using force-stop
- Never delete or hand-edit identity metadata in the database root
- Use proxy.Shutdown for v2 verifiable records; reserve ForceStopUnverified for legacy ones
- Confirm rootDir is the actual workspace root
When it happens
Trigger: Calling ForceStopUnverified when requireUnverifiableRecord calls identity.RootID(rootDir) and it errors (e.g. workspace identity file missing/corrupt, unreadable directory), so verifiability of the record cannot be established.
Common situations: Workspaces partially migrated between record format versions (v1 legacy vs v2 identity), identity metadata deleted or corrupted, or the rootDir passed is not the actual workspace root.
Related errors
- identity: request refused
- identity: oversized reply
- identity: invalid reply MAC
- identity: reply authentication failed
- identity: invalid request nonce
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/4dc4e7e981395669.
Report an issue: GitHub.