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

  1. Verify the endpoint is genuine PostgreSQL and not a malformed proxy target.
  2. Eliminate any SASL-rewriting middleware between client and server.
  3. 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

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


AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04). Data as JSON: /data/errors/eff5be248ec8d84e.json. Report an issue: GitHub.