gastownhall/beads · error

identity: write request: %w

Error message

identity: write request: %w

What it means

Identify writes the IDENT request line (secret + nonce) to the control connection. This error wraps the io.WriteString failure, meaning the TCP write failed after dialing — the connection broke mid-handshake.

Source

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

// 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
	}
	if err != nil {
		return nil, fmt.Errorf("identity: read reply: %w", err)
	}
	if len(line) > maxIdentReplyBytes {
		return nil, errors.New("identity: oversized reply")
	}

	var reply IdentReply
	if err := json.Unmarshal([]byte(line), &reply); err != nil {
		return nil, fmt.Errorf("identity: decode reply: %w", err)
	}
	if err := VerifyIdentReply(reply, secret, nonce); err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Confirm the port is actually the proxy's control listener speaking the IDENT protocol
  2. Increase the timeout so the write is not cut off
  3. Check proxy logs for a crash or early connection close
  4. Retry; if the listener is flapping, restart the proxy
Defensive patterns

Strategy: retry

Try / catch

reply, err := Identify(host, port, secret, timeout)
if err != nil && strings.Contains(err.Error(), "write request") {
	// connection dropped mid-handshake; retry with backoff, check proxy health
}

Prevention

When it happens

Trigger: The control listener closed or reset the connection before/while the request was written; network drop between dial and write; write deadline already exceeded.

Common situations: Listener crashed or refused the connection immediately after accept; wrong service on the port that closes on unknown input; very tight timeout expiring between dial and write; intermediary firewall sending RST.

Related errors


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