PasswordMessage passed to postgres instance returns 'insufficient data left in message'
Describe the bug
When proxying messages from the psql cli to a postgres instance (using a Backend for the client and a Frontend for the DB, I can successfully pass most messages back and forth until it gets to the PasswordMessage. When I proxy that to the database, it returns the error:
FATAL 08P01 insufficient data left in message
To Reproduce Steps to reproduce the behavior:
If possible, please provide runnable example such as:
package main
# the code has a channel of the messages going back and forth, so it can keep the sequence in order.
# I'd be happy to spin up an example codebase with a working copy of the code or something, but it feels too big to drop in a bug report
switch msg := unCast.(type) {
case *pgproto3.SSLRequest:
_, err := p.clientConn.Write([]byte("N"))
if err != nil {
return err
}
case *pgproto3.StartupMessage:
p.username = msg.Parameters["user"]
p.databaseFrontend.Send(msg)
p.databaseFrontend.Flush()
case *pgproto3.AuthenticationSASL:
p.clientBackend.Send(msg)
p.clientBackend.Flush()
case *pgproto3.PasswordMessage:
p.databaseFrontend.Send(msg)
p.databaseFrontend.Flush()
case *pgproto3.ErrorResponse:
p.clientBackend.Send(msg)
p.clientBackend.Flush()
}
Expected behavior I expect the message from the client to be received without error by the postgres database, and for the initialization handshake to continue.
Actual behavior
msg c->db (*pgproto3.SSLRequest): &{}
msg c->db (*pgproto3.StartupMessage): ....
msg db->c (*pgproto3.AuthenticationSASL): &{[SCRAM-SHA-256]}
msg c->db (*pgproto3.PasswordMessage): &{SCRAM-SHA-256}
msg db->c (*pgproto3.ErrorResponse): &{FATAL FATAL 08P01 insufficient data left in message %!!(MISSING)s(int32=0) %!!(MISSING)s(int32=0) pqformat.c %!!(MISSING)s(int32=531) pq_copymsgbytes map[]}
Version
- Go: go version go1.23.2 linux/amd64
- PostgreSQL: postgres:17 docker image
- pgx: github.com/jackc/pgx/v5 v5.7.1
I've proxied the PG protocol before, but I've never done it with SSL or SASL. I would suggest trying it without SSL and maybe with a simpler password type. I wonder if psql is trying to use channel binding or something else not supported by pgx.
Good info, thanks.
I'm currently injecting a N to ssl requests, but I'll give a simpler auth method a try.
Interestingly im able to make it work by proxying net.Conn communication, then when I see a Q message, i wrap those connections with pgproto3 frontend/backend, and operate at a higher level. I was just hoping to keep it with the nice higher level library. :)
Clarification
The problem occurs because pgproto3.Backend requires its AuthType to be explicitly set to correctly parse authentication-related messages. If this state isn't synchronized with the upstream server (frontend), the backend will fail to handle messages like AuthenticationCleartextPassword, AuthenticationMD5Password, AuthenticationSASL, etc.
Resolution
You have to manually do something like:
backend.SetAuthType(frontend.GetAuthType())while reading from the frontend when possible.
Not the original poster but I can confirm that @alash3al 's solution works. When you receive authentication methods from the backend you are proxying, you have to call SetAuthType or the p message will be processed as an empty pgproto3.PasswordMessage struct and then if you forward that to the backend you will get this error.
This Github issue saved me hours!