t8y2/dbx · error

decode ZooKeeper session password: %w

Error message

decode ZooKeeper session password: %w

What it means

The final field of the ZooKeeper connect response is the session password as a length-prefixed byte slice; if decoder.bytes() cannot read it, this wrapped error is returned. It is the last decode step of the handshake, so a failure here means the frame was almost complete but truncated or malformed at the tail.

Source

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

		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
	}
	return int32(milliseconds)
}

View on GitHub (pinned to c0390bff16)

Solutions

  1. Verify the password field is present with a correct 4-byte length prefix followed by exactly that many bytes
  2. Fix the test fake/handler to append the password bytes after the session ID
  3. Inspect intermediaries for frame truncation and compare against a direct connection capture
  4. Confirm ZooKeeper client/server wire-format compatibility

Example fix

// before (fake server)
resp := append(version, timeout...)
resp = append(resp, sessionID...) // password omitted
// after
resp = append(resp, sessionID...)
resp = append(resp, int32(len(passwd)))
resp = append(resp, passwd...)
Defensive patterns

Strategy: type-guard

Validate before calling

func frameHasPassword(decoder *zooKeeperDecoder) bool {
    return decoder.remaining() >= 4 // at least the password length prefix remains
}

Try / catch

client, err := newProtocolZooKeeperClient(conn, timeout)
if err != nil {
    if strings.Contains(err.Error(), "decode ZooKeeper session password") {
        log.Error("connect response truncated at password field; fix frame length or length prefix")
    }
    return err
}

Prevention

When it happens

Trigger: newProtocolZooKeeperClient decoding a response where the password length prefix or its bytes run past the end of the frame — truncated tail, wrong length prefix, or a fake response built without the password field.

Common situations: Manually crafted test responses missing the password bytes; frame off-by-one in a custom proxy; server implementations or versions emitting a different trailing layout.

Related errors


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