{"record":{"id":"02487e9378f404a8","repo":"brianc/node-postgres","slug":"sasl-scram-server-final-message-server-signature-02487e","errorCode":null,"errorMessage":"SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature is missing","messagePattern":"SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature is missing","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/pg/lib/crypto/sasl.js","lineNumber":232,"sourceCode":"\n  return {\n    nonce,\n    salt,\n    iteration,\n  }\n}\n\nfunction parseServerFinalMessage(serverData) {\n  const attrPairs = parseAttributePairs(serverData)\n  const error = attrPairs.get('e')\n  const serverSignature = attrPairs.get('v')\n\n  if (error) {\n    throw new Error(`SASL: SCRAM-SERVER-FINAL-MESSAGE: server returned error: \"${error}\"`)\n  }\n\n  if (!serverSignature) {\n    throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature is missing')\n  } else if (!isBase64(serverSignature)) {\n    throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature must be base64')\n  }\n  return {\n    serverSignature,\n  }\n}\n\nfunction xorBuffers(a, b) {\n  if (!Buffer.isBuffer(a)) {\n    throw new TypeError('first argument must be a Buffer')\n  }\n  if (!Buffer.isBuffer(b)) {\n    throw new TypeError('second argument must be a Buffer')\n  }\n  if (a.length !== b.length) {\n    throw new Error('Buffer lengths must match')\n  }","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/brianc/node-postgres/blob/ff9d775abd12f29dd6df03945253b54eabbb29f2/packages/pg/lib/crypto/sasl.js#L214-L250","documentation":"Thrown by parseServerFinalMessage() when the server's final SASL message lacks the v= attribute (verifier/signature) AND has no e= attribute (error). After confirming there is no error, the parser expects a server signature to verify. Its absence means the server sent an incomplete final message.","triggerScenarios":"At sasl.js:231-232, attrPairs.get('e') is falsy (no error) and attrPairs.get('v') is also falsy (no signature). The server's final message contains neither an error nor a verifier — it is missing the critical v= attribute.","commonSituations":"Malformed or truncated server final message; a non-conformant server that doesn't fully implement the SCRAM final message format; a proxy truncating the authentication exchange; network data loss cutting the final message before the signature attribute.","solutions":["Verify the target is a standard PostgreSQL server with full SCRAM-SHA-256 support.","Remove intermediaries that might truncate the SASL final message.","Test the connection with psql using the same connection string.","Enable SSL/TLS to protect the authentication stream.","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('server signature is missing')) {\n    throw new Error('SCRAM final message missing signature — verify server is PostgreSQL 10+ and no proxy truncates traffic')\n  }\n  throw err\n}","preventionTips":["Verify the target is a standard PostgreSQL server with full SCRAM-SHA-256 support.","Remove intermediaries that might truncate the SASL final message.","Test with psql using the same connection string.","Enable SSL/TLS to protect the authentication stream."],"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"}