{"record":{"id":"741f24558ab59018","repo":"brianc/node-postgres","slug":"sasl-scram-server-first-message-nonce-missing","errorCode":null,"errorMessage":"SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing","messagePattern":"SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/pg/lib/crypto/sasl.js","lineNumber":197,"sourceCode":"\n  return new Map(\n    text.split(',').map((attrValue) => {\n      if (!/^.=/.test(attrValue)) {\n        throw new Error('SASL: Invalid attribute pair entry')\n      }\n      const name = attrValue[0]\n      const value = attrValue.substring(2)\n      return [name, value]\n    })\n  )\n}\n\nfunction parseServerFirstMessage(data) {\n  const attrPairs = parseAttributePairs(data)\n\n  const nonce = attrPairs.get('r')\n  if (!nonce) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing')\n  } else if (!isPrintableChars(nonce)) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce must only contain printable characters')\n  }\n  const salt = attrPairs.get('s')\n  if (!salt) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: salt missing')\n  } else if (!isBase64(salt)) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: salt must be base64')\n  }\n  const iterationText = attrPairs.get('i')\n  if (!iterationText) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: iteration missing')\n  } else if (!/^[1-9][0-9]*$/.test(iterationText)) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: invalid iteration count')\n  }\n  const iteration = parseInt(iterationText, 10)\n\n  return {","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/brianc/node-postgres/blob/ff9d775abd12f29dd6df03945253b54eabbb29f2/packages/pg/lib/crypto/sasl.js#L179-L215","documentation":"Thrown by parseServerFirstMessage() when the server's first SASL message lacks the r= attribute (the combined client-server nonce). Per RFC 5802, the server's first message must include r=<client-nonce><server-nonce>. A missing nonce makes the SCRAM exchange impossible to continue.","triggerScenarios":"At sasl.js:195-196, attrPairs.get('r') returns a falsy value (undefined). This means the parsed attribute Map from the server's first message has no 'r' key — the server omitted the nonce entirely.","commonSituations":"Malformed or truncated server first message; connecting to a non-conformant PostgreSQL-compatible server; a proxy stripping or corrupting the authentication message; network data loss truncating the message before the nonce attribute.","solutions":["Verify the target is a standard PostgreSQL server supporting SCRAM-SHA-256 (PostgreSQL 10+).","Eliminate proxies or middleboxes that might truncate or alter the SASL message.","Test the same connection with psql to isolate whether the issue is server-side or client-side.","Update node-postgres to the latest version."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await client.connect()\n} catch (err) {\n  if (err.message.includes('nonce missing')) {\n    // Server's first SASL message is malformed — likely a non-conformant server or proxy corruption\n    throw new Error('SCRAM handshake failed: server sent no nonce')\n  }\n  throw err\n}","preventionTips":["Verify the target is PostgreSQL 10+ with SCRAM-SHA-256 enabled.","Eliminate proxies or middleboxes that might truncate the SASL message.","Test with psql to confirm the server's SASL handshake is correct.","Enable SSL/TLS to prevent data corruption in transit."],"tags":["authentication","sasl","scram","protocol-error","connection"],"backgroundTag":null,"analyzedSha":"ff9d775abd12f29dd6df03945253b54eabbb29f2","analyzedAt":"2026-08-11T15:33:59.644Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}