brianc/node-postgres · error · Error

SASL: SCRAM-SERVER-FIRST-MESSAGE: salt missing

Error message

SASL: SCRAM-SERVER-FIRST-MESSAGE: salt missing

What it means

Thrown by parseServerFirstMessage (sasl.js:201-203) when the server's first SCRAM message has no 's' attribute (the salt). The salt is mandatory per RFC 5802 §5.1; it is used as input to PBKDF2 for key derivation. Its absence means the client cannot derive the salted password and the authentication exchange is incomplete. The code reads attrPairs.get('s') and throws if falsy.

Source

Thrown at packages/pg/lib/crypto/sasl.js:203

      const name = attrValue[0]
      const value = attrValue.substring(2)
      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,
  }
}

View on GitHub (pinned to c5e8c9a57b)

Solutions

  1. Verify you are connecting to a genuine PostgreSQL server.
  2. Check that no intermediary (PgBouncer, load balancer) is modifying or truncating SASL messages.
  3. Enable SSL to ensure authentication message integrity.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await client.connect();
} catch (err) {
  if (/salt missing/i.test(err.message)) {
    console.error('SCRAM first message missing salt — non-compliant server or truncated message.');
  }
  throw err;
}

Prevention

When it happens

Trigger: The server's AuthenticationSASLContinue payload lacks the s=<salt> attribute. Parsed from serverData in continueSession -> parseServerFirstMessage.

Common situations: A non-compliant server sending an incomplete SCRAM first message. A proxy truncating the message. Wire-level corruption. Rare with genuine PostgreSQL backends.

Related errors


AI-assisted analysis of brianc/node-postgres@c5e8c9a57b (2026-08-03). Data as JSON: /data/errors/91f8b3cb0cd8ee74.json. Report an issue: GitHub.