gastownhall/beads · error
proxy.ForceStopUnverified: read %s: %w
Error message
proxy.ForceStopUnverified: read %s: %w
What it means
readForceStopRecord parses the PID/lock record file used by force-stop and wraps any read or parse failure in this error. It is thrown when the record exists but cannot be read/decoded, so ForceStopUnverified cannot determine the target PID and aborts instead of guessing.
Source
Thrown at internal/storage/dbproxy/proxy/force_stop.go:161
if err := inspectAndStopUnverifiedPID(rootDir, record.Pid, deadline, report); err != nil {
return err
}
return quarantineForceStopRecord(rootDir, pidName, record, report)
}
func readForceStopRecord(rootDir, pidName string, report *ForceStopReport) (*pidfile.PidFile, error) {
record, err := pidfile.Read(rootDir, pidName)
if err != nil {
if isMalformedPIDFileError(err) {
return nil, unverifiableProcessError(
"force-stop",
report.RecordPath,
0,
err,
unverifiableProcessChecks{},
)
}
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)View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the record file at report.RecordPath; if it is empty or corrupt and no live process owns it, delete it and retry
- Check the wrapped cause (%w) for the specific decode/IO error
- Retry the force-stop after any concurrent bd process finishes writing the record
- Recreate a healthy state by running a normal bd command in the workspace, which rewrites the records
Example fix
// before
record, err := readForceStopRecord(rootDir, pidName, report)
// after
record, err := readForceStopRecord(rootDir, pidName, report)
if err != nil {
if data, readErr := os.ReadFile(report.RecordPath); readErr == nil && len(bytes.TrimSpace(data)) == 0 {
_ = os.Remove(report.RecordPath)
record, err = readForceStopRecord(rootDir, pidName, report)
}
} Defensive patterns
Strategy: retry
Validate before calling
func recordReadable(path string) error {
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return nil // no record is fine
}
return err
}
_, perr := strconv.Atoi(strings.TrimSpace(string(data)))
return perr
} Try / catch
report, err := proxy.ForceStopUnverified(rootDir)
if err != nil && strings.Contains(err.Error(), "read ") {
// retry once; a concurrent writer may have been mid-write
time.Sleep(500 * time.Millisecond)
report, err = proxy.ForceStopUnverified(rootDir)
} Prevention
- Do not edit PID/record files by hand
- Retry transient read failures once before escalating
- Let bd commands regenerate records rather than restoring partial ones
- Watch for concurrent bd processes writing the same workspace
When it happens
Trigger: Calling ForceStopUnverified when readForceStopRecord fails to read or decode <rootDir>/<pidName> (e.g. truncated PID file, non-numeric content, transient I/O error) — after the lock was determined to be held.
Common situations: A PID file partially written by a crashed process, manual edits to PID/lock files, or a concurrent writer racing with the force-stop read.
Related errors
- proxy.ForceStopUnverified: record %s has invalid pid %d
- proxy.ForceStopUnverified: inspect executable for pid %d: %w
- proxy.ForceStopUnverified: refusing to signal pid %d from %s
- proxy.ForceStopUnverified: confirm pid %d exit: %w
- proxy.ForceStopUnverified: re-read %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/5717ba923725ca5c.
Report an issue: GitHub.