{"id":"ada7ead636a7dcf9","repo":"brianc/node-postgres","slug":"sasl-scram-server-first-message-client-password-ada7ea","errorCode":null,"errorMessage":"SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a non-empty string","messagePattern":"SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a non-empty string","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/pg/lib/crypto/sasl.js","lineNumber":70,"sourceCode":"\n  return {\n    mechanism,\n    clientNonce,\n    response: gs2Header + ',,n=*,r=' + clientNonce,\n    message: 'SASLInitialResponse',\n    scramMaxIterations,\n  }\n}\n\nasync function continueSession(session, password, serverData, stream) {\n  if (session.message !== 'SASLInitialResponse') {\n    throw new Error('SASL: Last message was not SASLInitialResponse')\n  }\n  if (typeof password !== 'string') {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string')\n  }\n  if (password === '') {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a non-empty string')\n  }\n  if (typeof serverData !== 'string') {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: serverData must be a string')\n  }\n\n  const sv = parseServerFirstMessage(serverData)\n\n  if (!sv.nonce.startsWith(session.clientNonce)) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce does not start with client nonce')\n  } else if (sv.nonce.length === session.clientNonce.length) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce is too short')\n  }\n\n  const scramMaxIterations =\n    typeof session.scramMaxIterations === 'number' ? session.scramMaxIterations : DEFAULT_MAX_SCRAM_ITERATIONS\n  // a value of 0 disables the iteration count check\n  if (scramMaxIterations !== 0 && sv.iteration > scramMaxIterations) {\n    throw new Error(","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/brianc/node-postgres/blob/c5e8c9a57bff6d9160ec5dbd5c4f4c1e4c460711/packages/pg/lib/crypto/sasl.js#L52-L88","documentation":"Thrown during SCRAM session continuation (sasl.js:69-71) when the password is an empty string (''). While SASLprep technically allows empty strings, node-postgres rejects them because an empty password for a SCRAM-authenticated role almost always indicates a configuration mistake (no password set) rather than an intentional empty-password role. The guard fires right after the type check and before PBKDF2 key derivation.","triggerScenarios":"The password resolves to '' — e.g., PGPASSWORD='' or { password: '' } — for a role that requires SCRAM authentication. Also when a .pgpass file contains an empty entry or a password provider returns ''.","commonSituations":"An env var like DB_PASSWORD is set but empty in a CI/staging environment. A config merge overwrote the password with an empty default. The connection string has an empty password segment: postgres://user:@host/db.","solutions":["Set a non-empty password via PGPASSWORD, the connection string, or the config object.","If using a password provider function, ensure it never returns '' for a SCRAM role.","Check for accidental empty-string defaults in config spread/merge logic (e.g., { password: process.env.DB_PASSWORD || '' })."],"exampleFix":"// before\nconst password = process.env.DB_PASSWORD || ''; // empty default\nconst client = new Client({ password });\n\n// after\nconst password = process.env.DB_PASSWORD;\nif (!password) throw new Error('DB_PASSWORD must be set');\nconst client = new Client({ password });","handlingStrategy":"validation","validationCode":"function ensureNonEmptyPassword(config) {\n  const pw = config.password ?? process.env.PGPASSWORD;\n  if (pw === '') {\n    throw new Error('Password is empty — set a non-empty password for SCRAM authentication');\n  }\n}","typeGuard":"function isNonEmptyPassword(pw) {\n  return typeof pw === 'string' && pw.length > 0;\n}","tryCatchPattern":"try {\n  await client.connect();\n} catch (err) {\n  if (/password must be a non-empty string/i.test(err.message)) {\n    console.error('Password resolved to empty string — check env/config for empty defaults.');\n  }\n  throw err;\n}","preventionTips":["Avoid empty-string defaults for password env vars (use undefined, not '').","Trim and validate passwords loaded from files or env before constructing the Client.","Fail fast at app startup if the password is missing rather than letting it reach the SASL layer."],"tags":["sasl","authentication","password","validation"],"analyzedSha":"c5e8c9a57bff6d9160ec5dbd5c4f4c1e4c460711","analyzedAt":"2026-08-03T18:47:28.334Z","schemaVersion":2}