t8y2/dbx · error
decode ZooKeeper session ID: %w
Error message
decode ZooKeeper session ID: %w
What it means
The connect response carries the 64-bit session ID; if decoder.int64() fails (not enough bytes left in the frame), newProtocolZooKeeperClient returns this error. A successful decode of 0 leads to zk.ErrSessionExpired instead, so this error strictly means the bytes could not be read, not an invalid session.
Source
Thrown at agents/drivers/argo-go/zookeeper_protocol.go:171
request.int64(0)
request.bytes(make([]byte, 16))
if err := client.writeFrame(request.data()); err != nil {
return nil, fmt.Errorf("send ZooKeeper connect request: %w", err)
}
response, err := client.readFrame()
if err != nil {
return nil, fmt.Errorf("read ZooKeeper connect response: %w", err)
}
decoder := newZooKeeperDecoder(response)
if _, err := decoder.int32(); err != nil {
return nil, fmt.Errorf("decode ZooKeeper protocol version: %w", err)
}
if _, err := decoder.int32(); err != nil {
return nil, fmt.Errorf("decode ZooKeeper session timeout: %w", err)
}
sessionID, err := decoder.int64()
if err != nil {
return nil, fmt.Errorf("decode ZooKeeper session ID: %w", err)
}
if _, err := decoder.bytes(); err != nil {
return nil, fmt.Errorf("decode ZooKeeper session password: %w", err)
}
if sessionID == 0 {
return nil, zk.ErrSessionExpired
}
return client, nil
}
func zooKeeperTimeoutMillis(timeout time.Duration) int32 {
milliseconds := timeout.Milliseconds()
if milliseconds < 1 {
return 1
}
if milliseconds > math.MaxInt32 {
return math.MaxInt32
}View on GitHub (pinned to c0390bff16)
Solutions
- Log/inspect the raw response frame and verify field sizes: int32 version, int32 timeout, int64 sessionID, bytes password
- Fix any intermediary (proxy/NAT) that fragments or truncates the stream
- Correct the encoder in test doubles to write the session ID as a full 8-byte int64
- Upgrade/align ZooKeeper client and server versions to the same wire protocol
Example fix
// before (test fake) buf.int32(0) // wrong: wrote sessionID as int32 // after buf.int32(0) buf.int32(30000) buf.int64(0x1234) // full 64-bit session ID buf.bytes(passwd)
Defensive patterns
Strategy: type-guard
Validate before calling
func frameHasSessionID(decoder *zooKeeperDecoder) bool {
return decoder.remaining() >= 8 // sessionID int64 after version+timeout
} Try / catch
client, err := newProtocolZooKeeperClient(conn, timeout)
if err != nil {
var expired = (err == zk.ErrSessionExpired) // note: sessionID==0 maps here, not this decode error
if !expired && strings.Contains(err.Error(), "decode ZooKeeper session ID") {
log.Error("connect response missing/truncated session ID")
}
return err
} Prevention
- Encode session IDs as full 8-byte values in fakes and tooling
- Validate field sizes (int32/int32/int64/bytes) when hand-crafting frames
- Compare against a wire capture from go-zk for layout correctness
When it happens
Trigger: newProtocolZooKeeperClient decoding a connect response shorter than the layout through the session-ID field (~12 bytes missing/misplaced) — truncated or mis-framed server data.
Common situations: Proxy or firewall clipping large frames; test fakes with wrong byte counts (int32 vs int64 confusion); server sending an error payload instead of the normal ConnectResponse structure.
Related errors
- decode ZooKeeper protocol version: %w
- decode ZooKeeper session timeout: %w
- decode ZooKeeper session password: %w
- decode ZooKeeper SASL round %d: %w
- ZooKeeper sent an unexpected token after GSSAPI completion
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/45b87192e0d584fb.
Report an issue: GitHub.