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 string
What it means
Thrown during SCRAM session continuation (sasl.js:66-68) when the password used for authentication is not a string. The SCRAM-SHA-256 protocol requires the plaintext password to derive a salted key via PBKDF2, so a non-string (number, object, null, undefined) cannot be processed. This is a client-side guard fired before any crypto operation, ensuring the type contract is met.
Source
Thrown at packages/pg/lib/crypto/sasl.js:67
const clientNonce = crypto.randomBytes(18).toString('base64')
const gs2Header = mechanism === 'SCRAM-SHA-256-PLUS' ? 'p=tls-server-end-point' : stream ? 'y' : 'n'
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_ITERATIONSView on GitHub (pinned to c5e8c9a57b)
Solutions
- Ensure the password is a string: set PGPASSWORD, add it to the connection string, or pass { password: '...' } to the Client/Pool config.
- If using a dynamic password provider (password as a function), make sure it resolves to a string.
- Verify the .pgpass file is readable if relying on it, though note pgpass support is deprecated.
Example fix
// before
const client = new Client({ user: 'me', host: 'localhost' }); // no password
// after
const client = new Client({
user: 'me',
host: 'localhost',
password: process.env.PGPASSWORD,
}); Defensive patterns
Strategy: type-guard
Validate before calling
function ensureStringPassword(config) {
const pw = config.password ?? process.env.PGPASSWORD;
if (typeof pw !== 'string') {
throw new TypeError('Password must be a string for SCRAM authentication');
}
config.password = pw;
} Type guard
function isStringPassword(password) {
return typeof password === 'string';
} Try / catch
try {
await client.connect();
} catch (err) {
if (/password must be a string/i.test(err.message)) {
console.error('Password is not set or not a string — check PGPASSWORD / config.');
}
throw err;
} Prevention
- Always provide a string password via config, connection string, or PGPASSWORD.
- If using a dynamic password function, ensure it resolves to a string.
- Add a startup assertion that the password env var exists and is a string.
When it happens
Trigger: The client's password property is undefined (e.g., PGPASSWORD not set and no password in config), or it was set to a non-string value like a number or an object. This surfaces inside continueSession when typeof password !== 'string'.
Common situations: PGPASSWORD env var is unset and no password is in the connection string/config for a role requiring SCRAM auth. A dynamic password provider function was used incorrectly and returned a non-string. The password was accidentally set to null in a config merge.
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/d6fc97cccf9e7b89.json.
Report an issue: GitHub.