t8y2/dbx · error

ZooKeeper response frame is %d bytes, maximum is %d

Error message

ZooKeeper response frame is %d bytes, maximum is %d

What it means

readFrame reads the 4-byte big-endian length header of a ZooKeeper response and rejects any declared length that is negative or exceeds zooKeeperMaxFrameSize. This guards against decoding an absurdly large buffer (unbounded allocation) when the peer is misbehaving, the stream is misaligned, or the connection is talking to something that is not a ZooKeeper server.

Source

Thrown at agents/drivers/argo-go/zookeeper_protocol.go:363

	header := make([]byte, 4)
	binary.BigEndian.PutUint32(header, uint32(len(payload)))
	if err := writeAll(client.connection, header); err != nil {
		return err
	}
	return writeAll(client.connection, payload)
}

func (client *protocolZooKeeperClient) readFrame() ([]byte, error) {
	if err := client.connection.SetReadDeadline(time.Now().Add(client.timeout)); err != nil {
		return nil, err
	}
	header := make([]byte, 4)
	if _, err := io.ReadFull(client.connection, header); err != nil {
		return nil, err
	}
	length := int(binary.BigEndian.Uint32(header))
	if length < 0 || length > zooKeeperMaxFrameSize {
		return nil, fmt.Errorf("ZooKeeper response frame is %d bytes, maximum is %d", length, zooKeeperMaxFrameSize)
	}
	payload := make([]byte, length)
	if _, err := io.ReadFull(client.connection, payload); err != nil {
		return nil, err
	}
	return payload, nil
}

func writeAll(writer io.Writer, payload []byte) error {
	for len(payload) > 0 {
		written, err := writer.Write(payload)
		if err != nil {
			return err
		}
		if written <= 0 {
			return io.ErrShortWrite
		}
		payload = payload[written:]

View on GitHub (pinned to c0390bff16)

Solutions

  1. Verify the connection address actually points to a ZooKeeper quorum member (default port 2181) — connect to a wrong service and its response bytes are parsed as a length header.
  2. Close and re-dial the client; the stream is likely desynchronized after an earlier error or timeout, and framing cannot recover mid-connection.
  3. Check for TLS/plaintext mismatch: if the server requires TLS and you dial plain TCP (or vice versa), the handshake bytes produce garbage lengths.
  4. Confirm any intermediary (proxy, port-forward) is TCP-transparent and not injecting data into the stream.
  5. If you legitimately need responses bigger than the cap, raise zooKeeperMaxFrameSize along with the server's jute.maxbuffer.

Example fix

// before
client, _, err := zk.Connect([]string{"10.0.0.5:80"}, time.Second*5) // wrong service/port

// after
client, _, err := zk.Connect([]string{"zk-1.internal:2181,zk-2.internal:2181"}, time.Second*5)
if err != nil {
    return err
}
client = client // re-dial on framing errors; do not reuse a connection after this error
Defensive patterns

Strategy: retry

Validate before calling

// validate the endpoint before dialing
host, port, err := net.SplitHostPort(connStr)
if err != nil || port != "2181" {
    return fmt.Errorf("suspicious ZooKeeper endpoint %q", connStr)
}
conn, err := net.DialTimeout("tcp", connStr, 3*time.Second)
if err != nil {
    return err
}
conn.Close()

Try / catch

resp, err := client.request(payload)
if err != nil && strings.Contains(err.Error(), "response frame is") {
    client.Close()
    client = redial() // framing is unrecoverable on this socket
    resp, err = client.request(payload) // bounded retry, once
}
if err != nil {
    return err
}

Prevention

When it happens

Trigger: Calling any request (Get/Children/Exists, etc.) when the response stream is desynchronized; connecting to a non-ZooKeeper service on the configured address; reading a partially-written or corrupted response; a length header whose bytes were shifted by a prior failed frame read.

Common situations: Wrong host/port in the ZooKeeper connection string (pointing at an HTTP server or another service that answers with bytes parsed as a giant length); a proxy/load balancer injecting HTML or TLS bytes; stale connection reused after a previous mid-frame timeout corrupted the framing.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/f5806a98963a8f40. Report an issue: GitHub.