{"record":{"id":"5717ba923725ca5c","repo":"gastownhall/beads","slug":"proxy-forcestopunverified-read-s-w","errorCode":null,"errorMessage":"proxy.ForceStopUnverified: read %s: %w","messagePattern":"proxy\\.ForceStopUnverified: read (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dbproxy/proxy/force_stop.go","lineNumber":161,"sourceCode":"\tif err := inspectAndStopUnverifiedPID(rootDir, record.Pid, deadline, report); err != nil {\n\t\treturn err\n\t}\n\treturn quarantineForceStopRecord(rootDir, pidName, record, report)\n}\n\nfunc readForceStopRecord(rootDir, pidName string, report *ForceStopReport) (*pidfile.PidFile, error) {\n\trecord, err := pidfile.Read(rootDir, pidName)\n\tif err != nil {\n\t\tif isMalformedPIDFileError(err) {\n\t\t\treturn nil, unverifiableProcessError(\n\t\t\t\t\"force-stop\",\n\t\t\t\treport.RecordPath,\n\t\t\t\t0,\n\t\t\t\terr,\n\t\t\t\tunverifiableProcessChecks{},\n\t\t\t)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"proxy.ForceStopUnverified: read %s: %w\", report.RecordPath, err)\n\t}\n\tif record == nil {\n\t\treturn nil, nil\n\t}\n\treport.RecordFound = true\n\treport.PID = record.Pid\n\treturn record, nil\n}\n\nfunc requireUnverifiableRecord(rootDir string, record *pidfile.PidFile, wantKind string) error {\n\tif err := record.ValidateV2(wantKind); err != nil {\n\t\treturn nil\n\t}\n\trootID, err := identity.RootID(rootDir)\n\tif err != nil {\n\t\t// Failing open here would route a possibly-verifiable record into the\n\t\t// destructive force path; surface the identity failure instead.\n\t\treturn fmt.Errorf(\"proxy.ForceStopUnverified: resolve workspace identity: %w\", err)","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/proxy/force_stop.go#L143-L179","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nrecord, err := readForceStopRecord(rootDir, pidName, report)\n// after\nrecord, err := readForceStopRecord(rootDir, pidName, report)\nif err != nil {\n    if data, readErr := os.ReadFile(report.RecordPath); readErr == nil && len(bytes.TrimSpace(data)) == 0 {\n        _ = os.Remove(report.RecordPath)\n        record, err = readForceStopRecord(rootDir, pidName, report)\n    }\n}","handlingStrategy":"retry","validationCode":"func recordReadable(path string) error {\n    data, err := os.ReadFile(path)\n    if err != nil {\n        if os.IsNotExist(err) {\n            return nil // no record is fine\n        }\n        return err\n    }\n    _, perr := strconv.Atoi(strings.TrimSpace(string(data)))\n    return perr\n}","typeGuard":null,"tryCatchPattern":"report, err := proxy.ForceStopUnverified(rootDir)\nif err != nil && strings.Contains(err.Error(), \"read \") {\n    // retry once; a concurrent writer may have been mid-write\n    time.Sleep(500 * time.Millisecond)\n    report, err = proxy.ForceStopUnverified(rootDir)\n}","preventionTips":["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"],"tags":["pidfile","parse-error","force-stop","corrupt-state"],"backgroundTag":"record-parse-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}