{"record":{"id":"b343639bca186875","repo":"t8y2/dbx","slug":"decode-zookeeper-session-timeout-w","errorCode":null,"errorMessage":"decode ZooKeeper session timeout: %w","messagePattern":"decode ZooKeeper session timeout: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/argo-go/zookeeper_protocol.go","lineNumber":167,"sourceCode":"\trequest := &zooKeeperEncoder{}\n\trequest.int32(zooKeeperProtocolVersion)\n\trequest.int64(0)\n\trequest.int32(zooKeeperTimeoutMillis(timeout))\n\trequest.int64(0)\n\trequest.bytes(make([]byte, 16))\n\tif err := client.writeFrame(request.data()); err != nil {\n\t\treturn nil, fmt.Errorf(\"send ZooKeeper connect request: %w\", err)\n\t}\n\tresponse, err := client.readFrame()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read ZooKeeper connect response: %w\", err)\n\t}\n\tdecoder := newZooKeeperDecoder(response)\n\tif _, err := decoder.int32(); err != nil {\n\t\treturn nil, fmt.Errorf(\"decode ZooKeeper protocol version: %w\", err)\n\t}\n\tif _, err := decoder.int32(); err != nil {\n\t\treturn nil, fmt.Errorf(\"decode ZooKeeper session timeout: %w\", err)\n\t}\n\tsessionID, err := decoder.int64()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"decode ZooKeeper session ID: %w\", err)\n\t}\n\tif _, err := decoder.bytes(); err != nil {\n\t\treturn nil, fmt.Errorf(\"decode ZooKeeper session password: %w\", err)\n\t}\n\tif sessionID == 0 {\n\t\treturn nil, zk.ErrSessionExpired\n\t}\n\treturn client, nil\n}\n\nfunc zooKeeperTimeoutMillis(timeout time.Duration) int32 {\n\tmilliseconds := timeout.Milliseconds()\n\tif milliseconds < 1 {\n\t\treturn 1","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/argo-go/zookeeper_protocol.go#L149-L185","documentation":"The second int32 in the ZooKeeper connect response is the negotiated session timeout; if the decoder cannot extract it, this wrapped error is returned. Like the protocol-version decode, it indicates the response frame is too short or does not follow the ConnectResponse wire format.","triggerScenarios":"newProtocolZooKeeperClient decoding a response whose payload ends after the first int32 (fewer than 8 bytes total in the expected positions) — truncated frames from a broken proxy or a fake/test server emitting malformed data.","commonSituations":"Custom or middlebox proxies truncating frames; hand-rolled test doubles returning incomplete responses; memory corruption/short writes between server and client; version skew producing a different field order.","solutions":["Verify the response frame length against the expected ConnectResponse layout (negotiated timeout, session id, passwd)","Bypass or reconfigure any TCP proxy/middleware and test a direct connection to ZooKeeper","Fix the test fake to emit a complete, well-formed connect response","Ensure client and server ZooKeeper protocol versions are compatible"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"func frameHasTimeout(decoder *zooKeeperDecoder) bool {\n    return decoder.remaining() >= 4 // timeout int32 after the version field\n}","typeGuard":null,"tryCatchPattern":"client, err := newProtocolZooKeeperClient(conn, timeout)\nif err != nil {\n    if strings.Contains(err.Error(), \"decode ZooKeeper session timeout\") {\n        log.Error(\"truncated ZK connect response; check proxy MTU/framing\")\n        return err\n    }\n    return err\n}","preventionTips":["Avoid custom proxies that re-frame the TCP stream; if used, test frame integrity","Keep client/server protocol versions aligned","Write complete ConnectResponses in test fakes (version+timeout+sessionID+passwd)","Capture a known-good response for regression tests"],"tags":["zookeeper","protocol","decoding"],"backgroundTag":"protocol-decode-failed","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}