brianc/node-postgres · error · Error
SASL: SCRAM-SERVER-FIRST-MESSAGE: salt must be base64
Error message
SASL: SCRAM-SERVER-FIRST-MESSAGE: salt must be base64
What it means
Thrown by parseServerFirstMessage() when the salt value from the s= attribute fails the isBase64() regex check. The salt must be valid standard base64 (alphabet A-Z, a-z, 0-9, +, / with correct = padding). Invalid base64 means the client cannot decode the salt bytes for PBKDF2.
Solutions
- Verify network integrity — check for corrupting intermediaries.
- Confirm the server is a standard PostgreSQL instance.
- Enable SSL/TLS to protect the authentication data stream.
- Test the connection with psql from the same environment.
Defensive patterns
Strategy: try-catch
Try / catch
try {
await client.connect()
} catch (err) {
if (err.message.includes('salt must be base64')) {
throw new Error('SCRAM salt is not valid base64 — check for data corruption or non-conformant server')
}
throw err
} Prevention
- Verify network integrity — check for corrupting proxies or encoding issues.
- Confirm the server is a standard PostgreSQL instance.
- Enable SSL/TLS to protect authentication data.
- Test with psql from the same environment to isolate server vs. client issues.
When it happens
Trigger: At sasl.js:204-205, isBase64(salt) returns false. The s= attribute value does not match the regex /^(?:[a-zA-Z0-9+/]{4})*(?:[a-zA-Z0-9+/]{2}==|[a-zA-Z0-9+/]{3}=)?$/ — it contains invalid characters, incorrect padding, or a length not divisible by 4.
Common situations: Data corruption in transit altering salt bytes; an encoding mismatch (e.g., URL-safe base64 with - and _ instead of + and /); a non-conformant server sending raw hex or another format; a proxy re-encoding the authentication stream.
Related errors
- SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature must be…
- SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce must only contain…
- SASL: Invalid attribute pair entry
- SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature is…
- SASL: SCRAM-SERVER-FIRST-MESSAGE: invalid iteration count
AI-assisted analysis of brianc/node-postgres@ff9d775abd (2026-08-11).
Data as JSON: /api/errors/6858bd8e95450e54.
Report an issue: GitHub.
Appendix: source
Thrown at packages/pg/lib/crypto/sasl.js:205
return [name, value]
})
)
}
function parseServerFirstMessage(data) {
const attrPairs = parseAttributePairs(data)
const nonce = attrPairs.get('r')
if (!nonce) {
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing')
} else if (!isPrintableChars(nonce)) {
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce must only contain printable characters')
}
const salt = attrPairs.get('s')
if (!salt) {
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: salt missing')
} else if (!isBase64(salt)) {
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: salt must be base64')
}
const iterationText = attrPairs.get('i')
if (!iterationText) {
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: iteration missing')
} else if (!/^[1-9][0-9]*$/.test(iterationText)) {
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: invalid iteration count')
}
const iteration = parseInt(iterationText, 10)
return {
nonce,
salt,
iteration,
}
}
function parseServerFinalMessage(serverData) {
const attrPairs = parseAttributePairs(serverData)View on GitHub (pinned to ff9d775abd)