{"record":{"id":"c0cfe4c834112866","repo":"t8y2/dbx","slug":"zookeeper-response-xid-d-does-not-match-request-x","errorCode":null,"errorMessage":"ZooKeeper response XID %d does not match request XID %d","messagePattern":"ZooKeeper response XID (.+?) does not match request XID (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/argo-go/zookeeper_protocol.go","lineNumber":323,"sourceCode":"\trequest.int32(client.xid)\n\trequest.int32(opcode)\n\tif encodeBody != nil {\n\t\tencodeBody(request)\n\t}\n\tif err := client.writeFrame(request.data()); err != nil {\n\t\treturn nil, err\n\t}\n\tresponse, err := client.readFrame()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdecoder := newZooKeeperDecoder(response)\n\txid, err := decoder.int32()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif xid != client.xid {\n\t\treturn nil, fmt.Errorf(\"ZooKeeper response XID %d does not match request XID %d\", xid, client.xid)\n\t}\n\tif _, err := decoder.int64(); err != nil {\n\t\treturn nil, err\n\t}\n\tcode, err := decoder.int32()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := zooKeeperError(code); err != nil {\n\t\treturn nil, err\n\t}\n\treturn decoder.remaining(), nil\n}\n\nfunc (client *protocolZooKeeperClient) writeFrame(payload []byte) error {\n\tif len(payload) > zooKeeperMaxFrameSize {\n\t\treturn fmt.Errorf(\"ZooKeeper request frame is %d bytes, maximum is %d\", len(payload), zooKeeperMaxFrameSize)\n\t}","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/argo-go/zookeeper_protocol.go#L305-L341","documentation":"ZooKeeper multiplexes concurrent requests over one connection using an incrementing transaction id (XID); request() verifies the XID in the response equals the XID sent for the current request. This error means the reply frame's XID does not match — the response stream has desynchronized from the request stream (a response was lost, duplicated, or out of order, or a server-pushed event/watch payload was misread as a response).","triggerScenarios":"client.request() (used by authenticateSASL, AddAuth, Children, Get) receives a frame whose leading int32 differs from client.xid: a previous response was dropped after a timeout while the server still sent it later, a frame from a prior/closed session arrives, or the byte stream is misaligned so a non-XID field is parsed as the XID.","commonSituations":"A previous call timed out at the read deadline but the server eventually replied, leaving the stale response in the socket buffer that the next request then reads; connection reuse across a reconnect without discarding buffered data; proxy/load-balancer interleaving frames; or session expiry causing the server to send a non-request-matched packet.","solutions":["Close and reopen the ZooKeeper connection: once the stream desyncs, every subsequent response will mismatch — reconnecting is the only reliable recovery.","Avoid ignoring earlier request errors: if a previous operation failed with a timeout, treat the connection as poisoned and redial rather than issuing new requests on it.","Ensure only one request is in flight per connection — the client serializes under client.mutex, so check for other users of the same socket (e.g. a wrapper or shared client) issuing concurrent frames.","Check for proxies/load balancers that multiplex or buffer ZooKeeper traffic; connect directly to the quorum members.","Inspect whether watch/event packets from the server could be interleaved on this connection in your deployment and filter them before request responses."],"exampleFix":"// before: reusing a connection after a timed-out request\n_, err := client.Get(\"/key\") // times out\n_, err = client.Get(\"/other\") // response XID 42 does not match request XID 43\n// after: redial on timeout before issuing another request\nif err != nil && isTimeout(err) {\n    client.Close()\n    client, err = zookeeper.Connect(hosts, timeout)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"_, err := client.Get(path)\nif err != nil {\n    if strings.Contains(err.Error(), \"does not match request XID\") {\n        // stream is desynced; the connection is unusable — redial\n        client.Close()\n        newClient, dialErr := zookeeper.Connect(hosts, timeout)\n        if dialErr != nil {\n            return dialErr\n        }\n        client = newClient\n        return retryOperation()\n    }\n    return err\n}","preventionTips":["Never reuse a connection after a timed-out request — treat timeouts as connection-fatal and redial.","Share the client only through its own mutex-serialized API; don't issue frames on the underlying socket from elsewhere.","Connect directly to quorum members; avoid multiplexing proxies in front of ZooKeeper.","Set read deadlines larger than worst-case server latency so responses are consumed before the client gives up."],"tags":["go","zookeeper","protocol","xid","stream-desync","concurrency"],"backgroundTag":"response-mismatch","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"}