gastownhall/beads · warning
verify proxy pid %d: %w
Error message
verify proxy pid %d: %w
What it means
readAndDial wraps failures from verifyProcessIdentity when probing the OS identity (PID + birth token) of the process recorded in the proxy pidfile. Instead of treating this as a stale/dead record, discovery classifies it as adoptionUnverifiable: the recorded PID may be live but cannot be safely confirmed, so the proxy is not adopted.
Source
Thrown at internal/storage/dbproxy/proxy/endpoint.go:598
return adoptionResult{status: adoptionNoRecord}
}
if err := pf.ValidateV2(pidfile.KindProxy); err != nil {
if errors.Is(err, pidfile.ErrLegacySchema) {
return adoptionResult{status: adoptionLegacy, pidfile: pf, err: err}
}
return adoptionResult{status: adoptionMalformed, pidfile: pf, err: err}
}
matched, err := verifyProcessIdentity(pf.Pid, procid.Token(pf.Birth))
if err != nil {
// Discovery must not turn an identity-probe failure into a fatal
// pidfile I/O error. In particular, Windows ERROR_ACCESS_DENIED on a
// recycled PID belongs in this non-adopting path; proxy.lock still
// gates quarantine and replacement.
return adoptionResult{
status: adoptionUnverifiable,
pidfile: pf,
err: fmt.Errorf("verify proxy pid %d: %w", pf.Pid, err),
}
}
if !matched {
return adoptionResult{status: adoptionStaleDead, pidfile: pf}
}
expectedRootID, err := resolveRootIdentity(rootDir)
if err != nil {
return adoptionResult{status: adoptionUnverifiable, pidfile: pf, err: err}
}
secret, err := readControlSecret(rootDir)
if err != nil {
return adoptionResult{status: adoptionUnverifiable, pidfile: pf, err: err}
}
reply, err := identity.Identify("127.0.0.1", pf.ControlPort, secret, identityProbeTimeout)
if err != nil {
return adoptionResult{status: adoptionIdentityMismatch, pidfile: pf, err: err}
}View on GitHub (pinned to 71377f2769)
Solutions
- Check whether the PID in the pidfile belongs to a live process (ps -p <pid> / Task Manager) and stop the old proxy if it does
- Re-run under the same user that started the proxy, or align container/user namespaces
- Delete/quarantine the pidfile (bd will quarantine under proxy.lock and spawn a fresh proxy)
- Inspect the wrapped OS error via errors.Unwrap for the specific errno and address it (permissions, PID visibility)
Example fix
// before
matched, err := verifyProcessIdentity(pf.Pid, procid.Token(pf.Birth))
// caller side
discovery := readAndDial(root)
if discovery.status == adoptionUnverifiable {
log.Printf("cannot verify pid %d: %v; refusing to adopt", discovery.pidfile.Pid, discovery.err)
}
// after: explicitly test identity before relying on an existing proxy
if pf, _ := pidfile.Read(root, pidfile.FileName("proxy")); pf != nil && !pidMatches(pf.Pid, pf.Birth) {
quarantineRecord(root, PIDFileName, time.Now()) // force fresh spawn
} Defensive patterns
Strategy: fallback
Type guard
func isUnverifiable(d adoptionResult) bool {
return d.status == adoptionUnverifiable && d.err != nil
} Try / catch
discovery := readAndDial(root)
if isUnverifiable(discovery) {
// do NOT adopt; let proxy.lock-gated quarantine + fresh spawn handle it
if err := quarantineForSpawn(root, discovery); err != nil { return err }
} Prevention
- Run all bd commands for a workspace as the same OS user
- Avoid sharing one workspace between host and container with different PID views
- On Windows, keep workspace paths out of multi-user temp dirs
- Treat an unverifiable record as stale: let the normal quarantine-and-spawn path replace it
When it happens
Trigger: pf.ValidateV2 succeeds and verifyProcessIdentity(pf.Pid, pf.Birth) returns an OS-level probe error — e.g. Windows ERROR_ACCESS_DENIED on a recycled PID, or OpenProcess/permission failures — before any identity matching can occur.
Common situations: PID was recycled by an unrelated process owned by another user (Windows access denied); running bd across user boundaries or in a container where the recorded PID is not visible; hardened security software denying process opens.
Related errors
- failed to create .beads directory: %v Windows Controlled Fo
- procid: terminate process: %w
- procid: get process exit code: %w
- procid: get process times: %w
- read backend record %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/1540101b01a9c153.
Report an issue: GitHub.