{"record":{"id":"c3decc64ab6e1562","repo":"gastownhall/beads","slug":"proxy-forcestopunverified-at-most-one-options-val","errorCode":null,"errorMessage":"proxy.ForceStopUnverified: at most one options value is allowed","messagePattern":"proxy\\.ForceStopUnverified: at most one options value is allowed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dbproxy/proxy/force_stop.go","lineNumber":58,"sourceCode":"// unverifiable proxy or backend record. It applies the same procedure to the\n// proxy record (proxy.pid) and the backend record (proxy-child.pid): a\n// pre-v2 managed-local deployment leaves BOTH as legacy records, so covering\n// only the proxy record would lock the advertised recovery out of the real\n// upgrade topology.\n//\n// For each record: when its lock is free, the function holds it while\n// inspecting, signaling, and quarantining the unchanged record. When the lock\n// is held (the usual pre-upgrade-proxy case), it first inspects and signals\n// the live PID, waits for the lock to become free, then quarantines only if\n// the record is unchanged. Both flows accept an already-gone recorded\n// process. An unverified live PID is never signaled unless its executable\n// basename is exactly bd or dolt (with an optional .exe suffix) AND its\n// command line scopes it to this workspace; where the platform cannot\n// establish that scope, force-stop refuses rather than guessing.\nfunc ForceStopUnverified(rootDir string, opts ...ForceStopOptions) (ForceStopReport, error) {\n\treport := ForceStopReport{RecordPath: pidfile.Path(rootDir, PIDFileName)}\n\tif len(opts) > 1 {\n\t\treturn report, errors.New(\"proxy.ForceStopUnverified: at most one options value is allowed\")\n\t}\n\ttimeout := shutdownConfirmDeadline\n\tif len(opts) == 1 && opts[0].Timeout != 0 {\n\t\ttimeout = opts[0].Timeout\n\t}\n\tif timeout <= 0 {\n\t\treturn report, fmt.Errorf(\"proxy.ForceStopUnverified: timeout must be positive, got %s\", timeout)\n\t}\n\tif err := advanceStopEpoch(rootDir); err != nil {\n\t\treturn report, fmt.Errorf(\"proxy.ForceStopUnverified: publish stop epoch: %w\", err)\n\t}\n\n\tproxyErr := forceStopRecord(rootDir, LockFileName, PIDFileName, pidfile.KindProxy, timeout, &report)\n\n\tbackendReport := ForceStopReport{RecordPath: pidfile.Path(rootDir, server.PIDFileName)}\n\tbackendErr := forceStopRecord(\n\t\trootDir,\n\t\tserver.LockFileName,","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/proxy/force_stop.go#L40-L76","documentation":"ForceStopUnverified accepts variadic ForceStopOptions but is defined to take at most one options value. Passing more than one is a programming error and is rejected up front before any destructive work. This keeps the API contract unambiguous about timeout configuration.","triggerScenarios":"Calling proxy.ForceStopUnverified(root, opt1, opt2) with two or more ForceStopOptions values.","commonSituations":"Copy-paste refactors that append an extra options value; wrapping helpers that spread plus pass an explicit option.","solutions":["Pass at most one ForceStopOptions value","Merge desired fields into a single ForceStopOptions struct","Call with no options to use the default shutdownConfirmDeadline"],"exampleFix":"// before\nreport, err := proxy.ForceStopUnverified(root, proxy.ForceStopOptions{Timeout: 5 * time.Second}, proxy.ForceStopOptions{})\n// after\nreport, err := proxy.ForceStopUnverified(root, proxy.ForceStopOptions{Timeout: 5 * time.Second})","handlingStrategy":"validation","validationCode":"func safeForceStop(root string, opts ...proxy.ForceStopOptions) (proxy.ForceStopReport, error) {\n    if len(opts) > 1 {\n        opts = opts[:1]\n    }\n    return proxy.ForceStopUnverified(root, opts...)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember ForceStopOptions is a single optional value, not a slice of configs","Centralize force-stop calls in one helper that normalizes options","Never spread user-supplied option slices into the call"],"tags":["go","api-misuse","validation"],"backgroundTag":"too-many-arguments","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}