{"record":{"id":"64bd15836abd1554","repo":"gastownhall/beads","slug":"identity-request-refused","errorCode":null,"errorMessage":"identity: request refused","messagePattern":"identity: request refused","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dbproxy/identity/control.go","lineNumber":25,"sourceCode":"\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"time\"\n)\n\nconst (\n\tmaxIdentReplyBytes = 4096\n\tidentNonceBytes    = 16\n)\n\n// ErrIdentRefused reports that a control listener closed the connection\n// without replying to an identity request.\nvar ErrIdentRefused = errors.New(\"identity: request refused\")\n\n// IdentReply is the authenticated identity published by a managed proxy.\ntype IdentReply struct {\n\tSchema      int    `json:\"schema\"`\n\tRole        string `json:\"role\"`\n\tRootID      string `json:\"root_id\"`\n\tUpstreamID  string `json:\"upstream_id\"`\n\tPID         int    `json:\"pid\"`\n\tBirth       string `json:\"birth\"`\n\tDataPort    int    `json:\"data_port\"`\n\tControlPort int    `json:\"control_port\"`\n\tMAC         string `json:\"mac\"`\n}\n\n// Identify authenticates to a proxy control listener and returns its identity.\nfunc Identify(host string, controlPort int, secret string, timeout time.Duration) (*IdentReply, error) {\n\taddr := net.JoinHostPort(host, strconv.Itoa(controlPort))\n\tconn, err := net.DialTimeout(\"tcp\", addr, timeout)","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/identity/control.go#L7-L43","documentation":"ErrIdentRefused is a package-level sentinel from the dbproxy identity package: the control listener closed the connection without sending any reply to an identity request. Identify returns it so callers can distinguish 'peer actively refused/hung up' from protocol-level failures like bad MAC or oversized reply.","triggerScenarios":"Calling Identify against a control socket whose listener rejected the connection (wrong path/permissions), crashed, or closed the socket before answering — the read returned EOF/close instead of a reply line.","commonSituations":"Managed proxy not yet started when identity is probed at startup; socket file left stale from a previous run; permission mismatch on the unix socket; proxy process crashed mid-handshake.","solutions":["Verify the proxy control listener is running and the socket path is correct before calling Identify","Retry with backoff — at startup the listener may not be accepting yet","Delete and recreate a stale socket file if a previous proxy run left it behind","Check proxy logs for a crash or explicit rejection at handshake time"],"exampleFix":"// before\nreply, err := identity.Identify(conn, secret)\nif err != nil { return err }\n// after\nreply, err := identity.Identify(conn, secret)\nif err != nil {\n    if errors.Is(err, identity.ErrIdentRefused) { return ErrProxyNotReady } // retry/wait for listener\n    return err\n}","handlingStrategy":"retry","validationCode":"if _, err := os.Stat(socketPath); err != nil { return ErrProxyNotRunning }","typeGuard":"func isIdentRefused(err error) bool { return errors.Is(err, identity.ErrIdentRefused) }","tryCatchPattern":"reply, err := identity.Identify(conn, secret)\nif err != nil {\n    if errors.Is(err, identity.ErrIdentRefused) { return waitAndRetry(socketPath, 3) }\n    return err\n}","preventionTips":["Start the managed proxy and wait for its control socket before probing identity","Retry Identify with backoff at startup — the listener may not be accepting yet","Remove stale socket files left by previous runs","Check proxy logs for crashes when refusal is persistent"],"tags":["identity","ipc","unix-socket","handshake"],"backgroundTag":"connection-refused","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}