gastownhall/beads · error

identity: oversized reply

Error message

identity: oversized reply

What it means

Identify reads a single newline-delimited JSON reply from the control connection and enforces a hard cap of maxIdentReplyBytes (4096). A reply longer than the cap is rejected outright — the peer is not speaking the identity protocol or is hostile, so no attempt is made to parse it.

Source

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

	}
	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 {
		return nil, err
	}
	return &reply, nil
}

// SignIdentReply authenticates reply for the nonce in an IDENT request.
// The MAC covers the raw nonce bytes followed by canonical JSON for every
// reply field except MAC.
func SignIdentReply(reply IdentReply, secret, nonce string) (IdentReply, error) {
	nonceBytes, err := decodeIdentNonce(nonce)
	if err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Confirm the socket belongs to the managed proxy and speaks the identity protocol (correct version/schema)
  2. Reject and re-dial; do not retry against the same peer without verifying its identity first
  3. Cap reads client-side as well so a hostile peer cannot exhaust memory before this check
  4. Audit who can connect to the control socket (filesystem permissions on the unix socket)

Example fix

// before
reply, err := identity.Identify(conn, secret)
if err != nil { log.Fatal(err) }
// after
reply, err := identity.Identify(conn, secret)
if err != nil {
    if strings.Contains(err.Error(), "oversized reply") { return ErrNotAProxyPeer } // wrong/hostile listener
    return err
}
Defensive patterns

Strategy: validation

Validate before calling

// client-side cap: never read unbounded from the control socket
limited := io.LimitReader(conn, identity.MaxIdentReplyBytes+1)

Type guard

func isOversizedReply(err error) bool { return strings.Contains(err.Error(), "oversized reply") }

Try / catch

if err != nil {
    if isOversizedReply(err) { conn.Close(); return ErrUntrustedPeer } // drop connection
    return err
}

Prevention

When it happens

Trigger: Calling Identify against a listener that answers the identity request with data exceeding 4096 bytes before the first newline — e.g. a misconfigured service, garbage/binary response, or an unauthenticated peer flooding the socket.

Common situations: Pointing identity discovery at the wrong socket (a different daemon that replies verbosely); a compromised or rogue process squatting on the control socket; protocol version mismatch producing large error payloads.

Related errors


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