brianc/node-postgres · error · Error
SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a
Error message
SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a non-empty string
What it means
Thrown during SCRAM session continuation (sasl.js:69-71) when the password is an empty string (''). While SASLprep technically allows empty strings, node-postgres rejects them because an empty password for a SCRAM-authenticated role almost always indicates a configuration mistake (no password set) rather than an intentional empty-password role. The guard fires right after the type check and before PBKDF2 key derivation.
Source
Thrown at packages/pg/lib/crypto/sasl.js:70
return {
mechanism,
clientNonce,
response: gs2Header + ',,n=*,r=' + clientNonce,
message: 'SASLInitialResponse',
scramMaxIterations,
}
}
async function continueSession(session, password, serverData, stream) {
if (session.message !== 'SASLInitialResponse') {
throw new Error('SASL: Last message was not SASLInitialResponse')
}
if (typeof password !== 'string') {
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string')
}
if (password === '') {
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a non-empty string')
}
if (typeof serverData !== 'string') {
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: serverData must be a string')
}
const sv = parseServerFirstMessage(serverData)
if (!sv.nonce.startsWith(session.clientNonce)) {
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce does not start with client nonce')
} else if (sv.nonce.length === session.clientNonce.length) {
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce is too short')
}
const scramMaxIterations =
typeof session.scramMaxIterations === 'number' ? session.scramMaxIterations : DEFAULT_MAX_SCRAM_ITERATIONS
// a value of 0 disables the iteration count check
if (scramMaxIterations !== 0 && sv.iteration > scramMaxIterations) {
throw new Error(View on GitHub (pinned to c5e8c9a57b)
Solutions
- Set a non-empty password via PGPASSWORD, the connection string, or the config object.
- If using a password provider function, ensure it never returns '' for a SCRAM role.
- Check for accidental empty-string defaults in config spread/merge logic (e.g., { password: process.env.DB_PASSWORD || '' }).
Example fix
// before
const password = process.env.DB_PASSWORD || ''; // empty default
const client = new Client({ password });
// after
const password = process.env.DB_PASSWORD;
if (!password) throw new Error('DB_PASSWORD must be set');
const client = new Client({ password }); Defensive patterns
Strategy: validation
Validate before calling
function ensureNonEmptyPassword(config) {
const pw = config.password ?? process.env.PGPASSWORD;
if (pw === '') {
throw new Error('Password is empty — set a non-empty password for SCRAM authentication');
}
} Type guard
function isNonEmptyPassword(pw) {
return typeof pw === 'string' && pw.length > 0;
} Try / catch
try {
await client.connect();
} catch (err) {
if (/password must be a non-empty string/i.test(err.message)) {
console.error('Password resolved to empty string — check env/config for empty defaults.');
}
throw err;
} Prevention
- Avoid empty-string defaults for password env vars (use undefined, not '').
- Trim and validate passwords loaded from files or env before constructing the Client.
- Fail fast at app startup if the password is missing rather than letting it reach the SASL layer.
When it happens
Trigger: The password resolves to '' — e.g., PGPASSWORD='' or { password: '' } — for a role that requires SCRAM authentication. Also when a .pgpass file contains an empty entry or a password provider returns ''.
Common situations: An env var like DB_PASSWORD is set but empty in a CI/staging environment. A config merge overwrote the password with an empty default. The connection string has an empty password segment: postgres://user:@host/db.
Related errors
- SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a
- SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature does not
- SASL: Invalid attribute pair entry
- SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing
- SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce must only contain pr
AI-assisted analysis of brianc/node-postgres@c5e8c9a57b (2026-08-03).
Data as JSON: /data/errors/ada7ead636a7dcf9.json.
Report an issue: GitHub.