{"record":{"id":"f5806a98963a8f40","repo":"t8y2/dbx","slug":"zookeeper-response-frame-is-d-bytes-maximum-is","errorCode":null,"errorMessage":"ZooKeeper response frame is %d bytes, maximum is %d","messagePattern":"ZooKeeper response frame is (.+?) bytes, maximum is (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/argo-go/zookeeper_protocol.go","lineNumber":363,"sourceCode":"\theader := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(header, uint32(len(payload)))\n\tif err := writeAll(client.connection, header); err != nil {\n\t\treturn err\n\t}\n\treturn writeAll(client.connection, payload)\n}\n\nfunc (client *protocolZooKeeperClient) readFrame() ([]byte, error) {\n\tif err := client.connection.SetReadDeadline(time.Now().Add(client.timeout)); err != nil {\n\t\treturn nil, err\n\t}\n\theader := make([]byte, 4)\n\tif _, err := io.ReadFull(client.connection, header); err != nil {\n\t\treturn nil, err\n\t}\n\tlength := int(binary.BigEndian.Uint32(header))\n\tif length < 0 || length > zooKeeperMaxFrameSize {\n\t\treturn nil, fmt.Errorf(\"ZooKeeper response frame is %d bytes, maximum is %d\", length, zooKeeperMaxFrameSize)\n\t}\n\tpayload := make([]byte, length)\n\tif _, err := io.ReadFull(client.connection, payload); err != nil {\n\t\treturn nil, err\n\t}\n\treturn payload, nil\n}\n\nfunc writeAll(writer io.Writer, payload []byte) error {\n\tfor len(payload) > 0 {\n\t\twritten, err := writer.Write(payload)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif written <= 0 {\n\t\t\treturn io.ErrShortWrite\n\t\t}\n\t\tpayload = payload[written:]","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/argo-go/zookeeper_protocol.go#L345-L381","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Close and re-dial the client; the stream is likely desynchronized after an earlier error or timeout, and framing cannot recover mid-connection.","Check for TLS/plaintext mismatch: if the server requires TLS and you dial plain TCP (or vice versa), the handshake bytes produce garbage lengths.","Confirm any intermediary (proxy, port-forward) is TCP-transparent and not injecting data into the stream.","If you legitimately need responses bigger than the cap, raise zooKeeperMaxFrameSize along with the server's jute.maxbuffer."],"exampleFix":"// before\nclient, _, err := zk.Connect([]string{\"10.0.0.5:80\"}, time.Second*5) // wrong service/port\n\n// after\nclient, _, err := zk.Connect([]string{\"zk-1.internal:2181,zk-2.internal:2181\"}, time.Second*5)\nif err != nil {\n    return err\n}\nclient = client // re-dial on framing errors; do not reuse a connection after this error","handlingStrategy":"retry","validationCode":"// validate the endpoint before dialing\nhost, port, err := net.SplitHostPort(connStr)\nif err != nil || port != \"2181\" {\n    return fmt.Errorf(\"suspicious ZooKeeper endpoint %q\", connStr)\n}\nconn, err := net.DialTimeout(\"tcp\", connStr, 3*time.Second)\nif err != nil {\n    return err\n}\nconn.Close()","typeGuard":null,"tryCatchPattern":"resp, err := client.request(payload)\nif err != nil && strings.Contains(err.Error(), \"response frame is\") {\n    client.Close()\n    client = redial() // framing is unrecoverable on this socket\n    resp, err = client.request(payload) // bounded retry, once\n}\nif err != nil {\n    return err\n}","preventionTips":["Double-check the ZooKeeper connection string (host:2181) — wrong ports/services are the top cause.","Never reuse a client connection after a framing/timeout error; always re-dial.","Ensure TLS settings match the server; a plaintext dial to a TLS port yields garbage lengths.","Keep intermediaries (proxies, port-forwards) TCP-transparent and free of injected data."],"tags":["zookeeper","frame-size","protocol","stream-corruption"],"backgroundTag":"malformed-response-frame","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}