gastownhall/beads · error

identity: request refused

Error message

identity: request refused

What it means

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.

Source

Thrown at internal/storage/dbproxy/identity/control.go:25

	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net"
	"strconv"
	"time"
)

const (
	maxIdentReplyBytes = 4096
	identNonceBytes    = 16
)

// ErrIdentRefused reports that a control listener closed the connection
// without replying to an identity request.
var ErrIdentRefused = errors.New("identity: request refused")

// IdentReply is the authenticated identity published by a managed proxy.
type IdentReply struct {
	Schema      int    `json:"schema"`
	Role        string `json:"role"`
	RootID      string `json:"root_id"`
	UpstreamID  string `json:"upstream_id"`
	PID         int    `json:"pid"`
	Birth       string `json:"birth"`
	DataPort    int    `json:"data_port"`
	ControlPort int    `json:"control_port"`
	MAC         string `json:"mac"`
}

// Identify authenticates to a proxy control listener and returns its identity.
func Identify(host string, controlPort int, secret string, timeout time.Duration) (*IdentReply, error) {
	addr := net.JoinHostPort(host, strconv.Itoa(controlPort))
	conn, err := net.DialTimeout("tcp", addr, timeout)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Verify the proxy control listener is running and the socket path is correct before calling Identify
  2. Retry with backoff — at startup the listener may not be accepting yet
  3. Delete and recreate a stale socket file if a previous proxy run left it behind
  4. Check proxy logs for a crash or explicit rejection at handshake time

Example fix

// before
reply, err := identity.Identify(conn, secret)
if err != nil { return err }
// after
reply, err := identity.Identify(conn, secret)
if err != nil {
    if errors.Is(err, identity.ErrIdentRefused) { return ErrProxyNotReady } // retry/wait for listener
    return err
}
Defensive patterns

Strategy: retry

Validate before calling

if _, err := os.Stat(socketPath); err != nil { return ErrProxyNotRunning }

Type guard

func isIdentRefused(err error) bool { return errors.Is(err, identity.ErrIdentRefused) }

Try / catch

reply, err := identity.Identify(conn, secret)
if err != nil {
    if errors.Is(err, identity.ErrIdentRefused) { return waitAndRetry(socketPath, 3) }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/64bd15836abd1554. Report an issue: GitHub.