gastownhall/beads · error
authenticated proxy identity does not match its pidfile or w
Error message
authenticated proxy identity does not match its pidfile or workspace
What it means
This error is returned by readAndDial when the freshly spawned/authenticated proxy's handshake reply does not match the pidfile or workspace (mismatched PID, data/control port, or UpstreamID). It indicates the process that answered is not the proxy this workspace owns, so adoption is refused and the record is quarantined.
Source
Thrown at internal/storage/dbproxy/proxy/endpoint.go:631
reply, err := identity.Identify("127.0.0.1", pf.ControlPort, secret, identityProbeTimeout)
if err != nil {
return adoptionResult{status: adoptionIdentityMismatch, pidfile: pf, err: err}
}
// Accept schema v2 or newer, matching pidfile.ValidateV2's forward-compat
// policy for records.
if reply.Schema < pidfile.SchemaV2 ||
reply.Role != pidfile.KindProxy ||
reply.RootID != expectedRootID ||
reply.RootID != pf.RootID ||
reply.PID != pf.Pid ||
reply.Birth != pf.Birth ||
reply.DataPort != pf.Port ||
reply.ControlPort != pf.ControlPort ||
reply.UpstreamID != pf.UpstreamID {
return adoptionResult{
status: adoptionIdentityMismatch,
pidfile: pf,
err: errors.New("authenticated proxy identity does not match its pidfile or workspace"),
}
}
ep := Endpoint{Host: "127.0.0.1", Port: pf.Port}
if !probePort(ep, identityProbeTimeout) {
return adoptionResult{
status: adoptionIdentityMismatch,
pidfile: pf,
err: fmt.Errorf("authenticated proxy data port %d is not accepting connections", pf.Port),
}
}
return adoptionResult{status: adoptionAdopted, endpoint: ep, pidfile: pf}
}
func probePort(ep Endpoint, timeout time.Duration) bool {
conn, err := net.DialTimeout("tcp", ep.Address(), timeout)
if err != nil {
return falseView on GitHub (pinned to 71377f2769)
Solutions
- Let the library quarantine the record (default behavior) and retry the start to get a clean spawn on a fresh port
- Check for port collisions with other workspaces or leftover processes (lsof/ss) and kill/avoid them
- Ensure only one beads instance manages the workspace at a time (use the stop-epoch/lock protocol)
Example fix
// before
res := readAndDial(rootDir, pf)
// caller assumes success
// after
res := readAndDial(rootDir, pf)
if res.status == adoptionIdentityMismatch {
// library already quarantined the foreign record; restart cleanly
return spawnFreshProxy(rootDir)
} Defensive patterns
Strategy: type-guard
Validate before calling
// before adopting, verify the listener identity
if !pidMatchesPidfile(reply.PID, pf) || reply.UpstreamID != pf.UpstreamID { return errForeignListener } Type guard
func isIdentityMismatch(status adoptionStatus) bool { return status == adoptionIdentityMismatch } Try / catch
res := readAndDial(rootDir, pf)
if res.status == adoptionIdentityMismatch {
// record already quarantined; start a clean proxy
return spawnFreshProxy(rootDir)
} Prevention
- Ensure one workspace owner at a time
- Avoid overlapping port allocations between instances
- Clean stale pidfiles before start
When it happens
Trigger: readAndDial adoption probe where reply.PID, DataPort, ControlPort, or UpstreamID differs from the pidfile values; a foreign listener answering on the expected port.
Common situations: Another process grabbed the port between spawn and handshake; PID reuse; two workspaces/instances sharing a port range; stale pidfile pointing at someone else's server.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- ErrMissingBirth
- identity: request refused
- identity: oversized reply
- identity: invalid reply MAC
- identity: reply authentication failed
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/10e6ee014206d78a.
Report an issue: GitHub.