jackc/pgx · error
bad auth type
Error message
bad auth type
What it means
Returned by AuthenticationCleartextPassword.Decode in pgproto3/authentication_cleartext_password.go:30 when the first 4 bytes of the message body do not equal AuthTypeCleartextPassword (3). It is a defensive re-check: the frontend's findAuthenticationMessageType already selected this struct from that same code, so in the standard pgconn path it cannot fire. It indicates either byte corruption between dispatch and decode or direct misuse of Decode on bytes whose auth-type code is not 3.
Source
Thrown at pgproto3/authentication_cleartext_password.go:30
type AuthenticationCleartextPassword struct{}
// Backend identifies this message as sendable by the PostgreSQL backend.
func (*AuthenticationCleartextPassword) Backend() {}
// Backend identifies this message as an authentication response.
func (*AuthenticationCleartextPassword) AuthenticationResponse() {}
// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
// type identifier and 4 byte message length.
func (dst *AuthenticationCleartextPassword) Decode(src []byte) error {
if len(src) != 4 {
return errors.New("bad authentication message size")
}
authType := binary.BigEndian.Uint32(src)
if authType != AuthTypeCleartextPassword {
return errors.New("bad auth type")
}
return nil
}
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *AuthenticationCleartextPassword) Encode(dst []byte) ([]byte, error) {
dst, sp := beginMessage(dst, 'R')
dst = pgio.AppendUint32(dst, AuthTypeCleartextPassword)
return finishMessage(dst, sp)
}
// MarshalJSON implements encoding/json.Marshaler.
func (src AuthenticationCleartextPassword) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
}{
Type: "AuthenticationCleartextPassword",View on GitHub (pinned to ec1a0befd2)
Solutions
- Route 'R' messages through Frontend.Receive / findAuthenticationMessageType instead of picking the Decode struct manually.
- If decoding manually, read the 4-byte auth code first and select the matching struct (3 => cleartext).
- Check for memory/buffer aliasing if the same buffer is reused across decode attempts.
Example fix
// before: wrong struct for the frame
var m pgproto3.AuthenticationCleartextPassword
m.Decode(md5Bytes) // -> "bad auth type"
// after: dispatch on the auth code like the frontend does
switch binary.BigEndian.Uint32(body) {
case pgproto3.AuthTypeCleartextPassword:
var m pgproto3.AuthenticationCleartextPassword
return m.Decode(body)
case pgproto3.AuthTypeMD5Password:
var m pgproto3.AuthenticationMD5Password
return m.Decode(body)
} Defensive patterns
Strategy: validation
Validate before calling
// When decoding 'R' frames manually, dispatch on the auth code first.
if len(body) >= 4 {
switch binary.BigEndian.Uint32(body) {
case pgproto3.AuthTypeCleartextPassword:
var m pgproto3.AuthenticationCleartextPassword
return m.Decode(body)
}
} Type guard
func isCleartextAuthFrame(body []byte) bool {
return len(body) == 4 && binary.BigEndian.Uint32(body) == pgproto3.AuthTypeCleartextPassword
} Prevention
- Use Frontend.Receive (which dispatches via findAuthenticationMessageType) instead of hand-picking the Decode struct.
- Switch on the 4-byte auth code before calling any Authentication*.Decode.
- Never reuse the underlying byte buffer across decode calls.
When it happens
Trigger: Calling Decode on a byte slice whose leading uint32 is not 3 (e.g. feeding MD5/SASL/GSS bytes into a cleartext struct), or memory/stream corruption that mutates the code after dispatch. Most realistic in custom protocol tools, proxies, fuzzers, or tests rather than normal pgx connections.
Common situations: Test or proxy code that hard-codes the wrong Authentication* struct for a given frame; a corrupted buffer; a hand-crafted fuzz input.
Related errors
AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04).
Data as JSON: /data/errors/a1e755c05639181f.json.
Report an issue: GitHub.