{"record":{"id":"5a271f15387516da","repo":"gastownhall/beads","slug":"discover-proxy-from-s-under-lock-w","errorCode":null,"errorMessage":"discover proxy from %s under lock: %w","messagePattern":"discover proxy from (.+?) under lock: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dbproxy/proxy/endpoint.go","lineNumber":246,"sourceCode":"\t\tcase adoptionAdopted:\n\t\t\treturn adoptedEndpoint(rootDir, want, discovery)\n\t\tcase adoptionIOErr:\n\t\t\treturn Endpoint{}, fmt.Errorf(\"discover proxy from %s: %w\", pidfile.Path(rootDir, PIDFileName), discovery.err)\n\t\t}\n\n\t\tlock, err := util.TryLock(filepath.Join(rootDir, LockFileName))\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\t// Re-read under proxy.lock. Another opener may have replaced the\n\t\t\t// record after our lock-free discovery.\n\t\t\tdiscovery = readAndDial(rootDir)\n\t\t\tif discovery.status == adoptionAdopted {\n\t\t\t\tlock.Unlock()\n\t\t\t\treturn adoptedEndpoint(rootDir, want, discovery)\n\t\t\t}\n\t\t\tif discovery.status == adoptionIOErr {\n\t\t\t\tlock.Unlock()\n\t\t\t\treturn Endpoint{}, fmt.Errorf(\"discover proxy from %s under lock: %w\", pidfile.Path(rootDir, PIDFileName), discovery.err)\n\t\t\t}\n\n\t\t\tmarkerActive, markerErr := inspectSpawnMarkerLocked(rootDir)\n\t\t\tif markerErr != nil {\n\t\t\t\tlock.Unlock()\n\t\t\t\treturn Endpoint{}, markerErr\n\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 {","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/proxy/endpoint.go#L228-L264","documentation":"Same PID-record I/O failure as the lock-free discovery error, but detected after this caller successfully acquired proxy.lock and re-read the record. This proves the record was unreadable even while holding the exclusive lock, ruling out a concurrent replacement race, so the library returns immediately instead of spawning. The wrapped cause is preserved for errors.Is/As inspection.","triggerScenarios":"GetCreateDatabaseProxyServerEndpoint acquired proxy.lock (no other opener held it), re-ran readAndDial, and the pidfile read still failed with an I/O error — e.g. the record exists but is unreadable due to permissions or filesystem errors.","commonSituations":"Mixed-UID ownership of the .beads workspace (agent runs as different user than initial setup); read-only bind mounts in CI containers; corrupted record from a partial write by an older binary.","solutions":["Fix read permissions on the pidfile for the current user (chown/chmod)","If the record is stale, remove it manually and retry the operation","Check for a read-only or full filesystem on the workspace mount","Run under the same user account that originally created the proxy"],"exampleFix":"// before\nerror: discover proxy from /repo/.beads/proxy.pid under lock: permission denied\n// after\n$ chmod u+r /repo/.beads/proxy.pid  # or rm -f if stale\n$ bd ready","handlingStrategy":"validation","validationCode":"// Under your own coordination, verify the record is readable before calling open\ninfo, err := os.Stat(filepath.Join(rootDir, \"proxy.pid\"))\nif err == nil && info.Mode().Perm()&0o400 == 0 {\n    os.Chmod(filepath.Join(rootDir, \"proxy.pid\"), 0o644)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Standardize umask/permissions when creating workspace files","Do not mix root and non-root bd runs in the same clone","Monitor for read-only remounts on CI runners"],"tags":["io","pidfile","lock","proxy"],"backgroundTag":"pidfile-io-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}