gastownhall/beads · error

identity: dial control listener: %w

Error message

identity: dial control listener: %w

What it means

Identify dials the dbproxy control TCP listener to authenticate and fetch the proxy's identity. This error wraps net.DialTimeout's failure — the TCP connection to host:controlPort could not be established.

Source

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

// 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)
	if err != nil {
		return nil, fmt.Errorf("identity: dial control listener: %w", err)
	}
	defer func() { _ = conn.Close() }()

	if err := conn.SetDeadline(time.Now().Add(timeout)); err != nil {
		return nil, fmt.Errorf("identity: set control deadline: %w", err)
	}
	nonceBytes := make([]byte, identNonceBytes)
	if _, err := rand.Read(nonceBytes); err != nil {
		return nil, fmt.Errorf("identity: generate request nonce: %w", err)
	}
	nonce := hex.EncodeToString(nonceBytes)
	if _, err := io.WriteString(conn, "IDENT "+secret+" "+nonce+"\n"); err != nil {
		return nil, fmt.Errorf("identity: write request: %w", err)
	}

	line, err := bufio.NewReader(io.LimitReader(conn, maxIdentReplyBytes+1)).ReadString('\n')
	if errors.Is(err, io.EOF) && len(line) == 0 {
		return nil, ErrIdentRefused

View on GitHub (pinned to 71377f2769)

Solutions

  1. Verify the proxy control listener is running and note its actual control port
  2. Confirm host and controlPort match the proxy's startup logs/config
  3. Test reachability with nc -vz host controlPort
  4. Check firewall/security-group rules for the control port

Example fix

// before
reply, err := Identify("localhost", 42881, secret, 2*time.Second) // port guess
// after
reply, err := Identify("localhost", proxy.ControlPort(), secret, 5*time.Second)
Defensive patterns

Strategy: retry

Validate before calling

conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, strconv.Itoa(controlPort)), timeout)
if err != nil { /* surface actionable message before calling Identify */ }

Try / catch

reply, err := Identify(host, port, secret, timeout)
if errors.Is(err, syscall.ECONNREFUSED) || strings.Contains(err.Error(), "dial control listener") {
	// wait for the proxy to start and retry with backoff
}

Prevention

When it happens

Trigger: Calling identity.Identify(host, controlPort, secret, timeout) when the control listener is not running, the port is wrong, the host is unreachable, or a firewall blocks the connection.

Common situations: Proxy daemon not started yet; stale/wrong control port from config; connecting from another container/network namespace; DNS resolving to the wrong interface; firewall dropping the port.

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/4a285b052f6d8992. Report an issue: GitHub.