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

  1. Route 'R' messages through Frontend.Receive / findAuthenticationMessageType instead of picking the Decode struct manually.
  2. If decoding manually, read the 4-byte auth code first and select the matching struct (3 => cleartext).
  3. 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

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.