{"record":{"id":"17b1f05c06f58302","repo":"gastownhall/beads","slug":"probe-proxy-lock-w","errorCode":null,"errorMessage":"probe proxy lock: %w","messagePattern":"probe proxy lock: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dbproxy/proxy/endpoint.go","lineNumber":271,"sourceCode":"\t\t\t}\n\t\t\tif markerActive {\n\t\t\t\tlock.Unlock()\n\t\t\t\tlastSpawnErr = nil\n\t\t\t\t// This break exits the switch only; the outer discovery loop\n\t\t\t\t// continues with its normal bounded poll.\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tvar ep Endpoint\n\t\t\tep, lastSpawnErr = spawnAndHandoff(rootDir, opts, deadline, stopEpoch, lock, discovery)\n\t\t\tif lastSpawnErr == nil {\n\t\t\t\treturn ep, nil\n\t\t\t}\n\t\t\tif errors.Is(lastSpawnErr, errStartInterrupted) {\n\t\t\t\treturn Endpoint{}, lastSpawnErr\n\t\t\t}\n\t\tcase !lockfile.IsLocked(err):\n\t\t\treturn Endpoint{}, fmt.Errorf(\"probe proxy lock: %w\", err)\n\t\tcase discovery.status == adoptionLegacy:\n\t\t\trecordPath := pidfile.Path(rootDir, PIDFileName)\n\t\t\treturn Endpoint{}, fmt.Errorf(\n\t\t\t\t\"legacy proxy record %s is protected by held lock %s; stop the pre-upgrade proxy with the old bd binary or wait for its idle exit, then quarantine the record manually by renaming %s to %s.stale-<unix-timestamp> before retrying\",\n\t\t\t\trecordPath,\n\t\t\t\tfilepath.Join(rootDir, LockFileName),\n\t\t\t\trecordPath,\n\t\t\t\trecordPath,\n\t\t\t)\n\t\t}\n\n\t\tselect {\n\t\tcase <-timeout.C:\n\t\t\tif lastSpawnErr != nil {\n\t\t\t\treturn Endpoint{}, lastSpawnErr\n\t\t\t}\n\t\t\treturn Endpoint{}, fmt.Errorf(\"timeout waiting for proxy on %s\", rootDir)\n\t\tcase <-poll.C:","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/proxy/endpoint.go#L253-L289","documentation":"This is not a lock-contention issue: util.TryLock failed with an error that is NOT 'lock already held' (lockfile.IsLocked(err) is false). That means the lock file itself could not be probed/created — an I/O or environmental failure — so the library cannot safely proceed and wraps the underlying error. Treat it as a filesystem problem, not a busy proxy.","triggerScenarios":"util.TryLock on <rootDir>/proxy.lock returns a non-IsLocked error: the lock file cannot be opened/created because the directory is missing or read-only, the OS lock syscall fails, or the lock path is invalid.","commonSituations":"Workspace directory deleted or renamed while bd was running; read-only mounts (CI cache restores, WSL cross-filesystem mounts); TMPDIR/overlay filesystem restrictions; running two tools with incompatible lock semantics on the same path.","solutions":["Verify <rootDir> exists and is writable; recreate the directory if it was removed","Check the mount is not read-only (mount | grep, or try touching a file in rootDir)","If a stale proxy.lock file exists but is not actually locked, remove it and retry","Re-run as a user with write access to the workspace"],"exampleFix":"// before\nerror: probe proxy lock: open /repo/.beads/proxy.lock: no such file or directory\n// after\n$ mkdir -p /repo/.beads && touch /repo/.beads/.write-test && rm /repo/.beads/.write-test\n$ bd ready","handlingStrategy":"try-catch","validationCode":"// Ensure the workspace is writable before attempting proxy open\nprobe := filepath.Join(rootDir, \".write-probe\")\nif err := os.WriteFile(probe, nil, 0o600); err != nil {\n    return fmt.Errorf(\"workspace not writable: %w\", err)\n}\nos.Remove(probe)","typeGuard":null,"tryCatchPattern":"err := proxy.GetCreateDatabaseProxyServerEndpoint(root, opts)\nvar lockErr *fs.PathError\nif err != nil && strings.HasPrefix(err.Error(), \"probe proxy lock:\") && errors.As(err, &lockErr) {\n    // filesystem-level lock failure: fix permissions/mount, do NOT busy-retry\n    return fmt.Errorf(\"fix workspace fs: %w\", err)\n}","preventionTips":["Health-check workspace writability at job start","Do not delete the workspace directory while bd processes are alive","Watch for noexec/read-only mount changes after CI cache restores"],"tags":["filesystem","lock","io","proxy"],"backgroundTag":"lock-file-unavailable","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}