{"record":{"id":"5235c24cc024f339","repo":"gastownhall/beads","slug":"proxy-forcestopunverified-timeout-acquiring-s-af","errorCode":null,"errorMessage":"proxy.ForceStopUnverified: timeout acquiring %s after signaling","messagePattern":"proxy\\.ForceStopUnverified: timeout acquiring (.+?) after signaling","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dbproxy/proxy/force_stop.go","lineNumber":297,"sourceCode":"\nfunc normalizeForceStopExecutable(name string) string {\n\tname = strings.TrimSpace(filepath.Base(name))\n\tname = strings.TrimSuffix(name, \" (deleted)\")\n\tname = strings.TrimSuffix(strings.ToLower(name), \".exe\")\n\treturn name\n}\n\nfunc acquireForceStopLock(lockPath string, deadline time.Time) (*util.Lock, error) {\n\tfor {\n\t\tlock, err := util.TryLock(lockPath)\n\t\tif err == nil {\n\t\t\treturn lock, nil\n\t\t}\n\t\tif !lockfile.IsLocked(err) {\n\t\t\treturn nil, fmt.Errorf(\"proxy.ForceStopUnverified: acquire %s: %w\", lockPath, err)\n\t\t}\n\t\tif time.Now().After(deadline) {\n\t\t\treturn nil, fmt.Errorf(\"proxy.ForceStopUnverified: timeout acquiring %s after signaling\", lockPath)\n\t\t}\n\t\ttime.Sleep(shutdownConfirmPoll)\n\t}\n}\n\nfunc quarantineForceStopRecord(\n\trootDir string,\n\tpidName string,\n\trecord *pidfile.PidFile,\n\treport *ForceStopReport,\n) error {\n\tcurrent, err := pidfile.Read(rootDir, pidName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"proxy.ForceStopUnverified: re-read %s: %w\", report.RecordPath, err)\n\t}\n\tif current == nil {\n\t\treturn nil\n\t}","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/proxy/force_stop.go#L279-L315","documentation":"This error is returned by acquireForceStopLock when, after signaling the unverified PID, the workspace lock stays continuously held by another process until the ForceStopUnverified deadline expires. The lock never became free within the timeout, so quarantine of the pidfile record was abandoned. This is contention, not a filesystem failure (that would be the 'acquire %s: %w' error).","triggerScenarios":"Call ForceStopUnverified (`bd dolt stop --force`) on a record whose lock was held (LockWasHeld=true); the PID was signaled, but the external lock holder (another bd/dolt process or stale lock) keeps the lock through every TryLock retry until deadline, so the post-signal acquire times out.","commonSituations":"Another long-running bd or dolt process legitimately holds the lock and ignores the killed record's PID; a stale lock left by a crashed process whose lockfile implementation does not auto-release (e.g. NFS without proper flock support); concurrent `bd dolt stop --force` invocations from multiple terminals racing each other.","solutions":["Identify the lock holder (fuser/lsof on the lock file, or ps for other bd/dolt processes) and stop it, then re-run `bd dolt stop --force`","Increase ForceStopOptions.Timeout if the holder is expected to release the lock soon (e.g. a finishing bd command)","If the lock is stale (holder is dead but lock persists, e.g. on NFS), remove the stale lock file only after confirming no live holder, then retry","Manually quarantine the record (rename proxy.pid to proxy.pid.stale-<unix-timestamp>) once you have confirmed the recorded process is gone"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Detect a live lock holder before calling force-stop:\n// fuser <rootDir>/proxy.lock  (or lsof <rootDir>/proxy.lock) — non-empty output means someone holds it","typeGuard":null,"tryCatchPattern":"report, err := proxy.ForceStopUnverified(rootDir, proxy.ForceStopOptions{Timeout: 60 * time.Second})\nif err != nil && strings.Contains(err.Error(), \"timeout acquiring\") {\n    // A holder kept the lock past the deadline: find and stop it, then retry\n    // fuser -k <rootDir>/proxy.lock  (only if the holder is confirmed to be yours)\n}","preventionTips":["Avoid running concurrent `bd dolt stop --force` invocations against the same workspace","Identify and gracefully stop other bd/dolt processes (bd doctor, running bd commands) before force-stopping","Increase ForceStopOptions.Timeout when a legitimate lock holder is expected to finish soon","On NFS, verify lock auto-release works; manually remove stale lock files only after confirming the holder is dead"],"tags":["file-lock","go","timeout","force-stop"],"backgroundTag":"lock-contention-timeout","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}