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() when the server's first SASL message lacks the s= attribute (the salt). Per RFC 5802, the server must provide a base64-encoded salt for the PBKDF2 key derivation. Without it, the client cannot derive the salted password.

Solutions

  1. Verify the target is a standard PostgreSQL server (10+) with SCRAM-SHA-256 properly configured.
  2. Remove any intermediary that might truncate the SASL message.
  3. Test with psql using the same connection string.
  4. Update node-postgres to the latest version.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await client.connect()
} catch (err) {
  if (err.message.includes('salt missing')) {
    throw new Error('SCRAM handshake failed: server sent no salt — verify server is PostgreSQL 10+')
  }
  throw err
}

Prevention

When it happens

Trigger: At sasl.js:201-202, attrPairs.get('s') returns a falsy value (undefined). The parsed attribute Map has no 's' key — the server omitted the salt from its first message.

Common situations: Malformed or truncated server first message; connecting to a non-conformant server that doesn't fully implement SCRAM-SHA-256; a proxy corrupting or truncating the authentication exchange; network data loss.

Related errors


AI-assisted analysis of brianc/node-postgres@ff9d775abd (2026-08-11). Data as JSON: /api/errors/91f8b3cb0cd8ee74. Report an issue: GitHub.

Appendix: 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 ff9d775abd)