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.

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.

Appendix: 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)