brianc/node-postgres · error · Error

SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce must only contain…

Error message

SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce must only contain printable characters

What it means

Thrown by parseServerFirstMessage() when the server's nonce contains characters outside the printable ASCII range defined by isPrintableChars() — specifically bytes 0x21-0x2B and 0x2D-0x7E (printable ASCII excluding comma). Per RFC 5802 the nonce must be printable. Non-printable characters could break the protocol's comma-delimited structure or indicate data corruption.

Solutions

  1. Verify network integrity between client and server — check for corrupting proxies, firewalls, or VPNs.
  2. Confirm the server is a legitimate PostgreSQL instance and not a spoofed/malicious endpoint.
  3. Enable SSL/TLS to protect the authentication stream from in-transit corruption.
  4. Test the connection with psql from the same host to isolate the issue.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await client.connect()
} catch (err) {
  if (err.message.includes('nonce must only contain printable characters')) {
    throw new Error('Data corruption in SASL nonce — check network integrity and SSL configuration')
  }
  throw err
}

Prevention

When it happens

Trigger: At sasl.js:198-199, isPrintableChars(nonce) returns false. The nonce value extracted from the r= attribute contains at least one character with a char code outside 0x21-0x2B or 0x2D-0x7E — e.g., a control character (0x00-0x1F), DEL (0x7F), a comma (0x2C), or a high byte (0x80+).

Common situations: Data corruption in transit introducing binary/noise bytes into the nonce field; a buggy or malicious server injecting crafted nonce values; an encoding mismatch where raw binary data leaks into a text field; a proxy that re-encodes or mangles the authentication stream.

Related errors


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

Appendix: source

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

    text.split(',').map((attrValue) => {
      if (!/^.=/.test(attrValue)) {
        throw new Error('SASL: Invalid attribute pair entry')
      }
      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,

View on GitHub (pinned to ff9d775abd)