jackc/pgx · error
invalid SCRAM server-first-message received from server: did
Error message
invalid SCRAM server-first-message received from server: did not include s=
What it means
Returned by recvServerFirstMessage when the server-first-message has 'r=<nonce>' but no comma separator follows, so the parser cannot find the required 's=' (salt) attribute. RFC 5802 requires the message to contain r=, then s=, then i=, comma-separated.
Source
Thrown at pgconn/auth_scram.go:254
sc.clientGS2Header = []byte("y,,")
default:
sc.clientGS2Header = []byte("n,,")
}
return append(sc.clientGS2Header, sc.clientFirstMessageBare...)
}
func (sc *scramClient) recvServerFirstMessage(serverFirstMessage []byte) error {
sc.serverFirstMessage = serverFirstMessage
buf := serverFirstMessage
if !bytes.HasPrefix(buf, []byte("r=")) {
return errors.New("invalid SCRAM server-first-message received from server: did not include r=")
}
buf = buf[2:]
idx := bytes.IndexByte(buf, ',')
if idx == -1 {
return errors.New("invalid SCRAM server-first-message received from server: did not include s=")
}
sc.clientAndServerNonce = buf[:idx]
buf = buf[idx+1:]
if !bytes.HasPrefix(buf, []byte("s=")) {
return errors.New("invalid SCRAM server-first-message received from server: did not include s=")
}
buf = buf[2:]
idx = bytes.IndexByte(buf, ',')
if idx == -1 {
return errors.New("invalid SCRAM server-first-message received from server: did not include i=")
}
saltStr := buf[:idx]
buf = buf[idx+1:]
if !bytes.HasPrefix(buf, []byte("i=")) {
return errors.New("invalid SCRAM server-first-message received from server: did not include i=")View on GitHub (pinned to ec1a0befd2)
Solutions
- Verify the endpoint is genuine PostgreSQL and not a malformed proxy target.
- Eliminate any SASL-rewriting middleware between client and server.
- Inspect the raw AuthenticationSASLContinue payload to confirm truncation, then report to the server/proxy vendor.
Defensive patterns
Strategy: try-catch
Try / catch
if err := connect(); err != nil && strings.Contains(err.Error(), "invalid SCRAM server-first-message") {
// Treat as a non-retryable protocol/tamper condition; alert ops.
return status.Errorf(codes.Unauthenticated, "auth exchange corrupted: %v", err)
} Prevention
- Ensure end-to-end TLS with certificate verification.
- Remove SASL-rewriting middleware.
- Capture a packet trace if it recurs to localize the corruption source.
When it happens
Trigger: Server sends a server-first-message like 'r=xyz' with no trailing comma/salt. Same class as a truncated/malformed SASL message from a non-conformant server or a tampering intermediary.
Common situations: Truncated network reads surfaced as a complete message by a buggy proxy; non-conformant server implementations; MITM tampering.
Related errors
- invalid SCRAM server-first-message received from server: did
- invalid SCRAM server-first-message received from server: did
- invalid SCRAM nonce: did not start with client nonce
- invalid SCRAM nonce: did not include server nonce
- invalid SCRAM server-final-message received from server
AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04).
Data as JSON: /data/errors/eff5be248ec8d84e.json.
Report an issue: GitHub.