{"id":"ac5c0cff8e1eb6f5","repo":"brianc/node-postgres","slug":"sasl-only-mechanism-s-candidates-join-and","errorCode":null,"errorMessage":"SASL: Only mechanism(s) ${candidates.join(' and ')} are supported","messagePattern":"SASL: Only mechanism\\(s\\) (.+?) are supported","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/pg/lib/crypto/sasl.js","lineNumber":42,"sourceCode":"  // RFC 3454 Table B.1 — \"commonly mapped to nothing\". The set intentionally\n  // contains zero-width joiners and variation selectors — the very characters\n  // ESLint's no-misleading-character-class warns about — because they combine\n  // with their neighbors and the RFC strips them for that reason.\n  // eslint-disable-next-line no-misleading-character-class\n  const mappedToNothing = /[\\u00AD\\u034F\\u1806\\u180B\\u180C\\u180D\\u200C\\u200D\\u2060\\uFE00-\\uFE0F\\uFEFF]/g\n  return password.replace(nonAsciiSpace, ' ').replace(mappedToNothing, '').normalize('NFKC')\n}\n\nconst DEFAULT_MAX_SCRAM_ITERATIONS = 100000\n\nfunction startSession(mechanisms, stream, scramMaxIterations = DEFAULT_MAX_SCRAM_ITERATIONS) {\n  const candidates = ['SCRAM-SHA-256']\n  if (stream) candidates.unshift('SCRAM-SHA-256-PLUS') // higher-priority, so placed first\n\n  const mechanism = candidates.find((candidate) => mechanisms.includes(candidate))\n\n  if (!mechanism) {\n    throw new Error('SASL: Only mechanism(s) ' + candidates.join(' and ') + ' are supported')\n  }\n\n  if (mechanism === 'SCRAM-SHA-256-PLUS' && typeof stream.getPeerCertificate !== 'function') {\n    // this should never happen if we are really talking to a Postgres server\n    throw new Error('SASL: Mechanism SCRAM-SHA-256-PLUS requires a certificate')\n  }\n\n  const clientNonce = crypto.randomBytes(18).toString('base64')\n  const gs2Header = mechanism === 'SCRAM-SHA-256-PLUS' ? 'p=tls-server-end-point' : stream ? 'y' : 'n'\n\n  return {\n    mechanism,\n    clientNonce,\n    response: gs2Header + ',,n=*,r=' + clientNonce,\n    message: 'SASLInitialResponse',\n    scramMaxIterations,\n  }\n}","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/brianc/node-postgres/blob/c5e8c9a57bff6d9160ec5dbd5c4f4c1e4c460711/packages/pg/lib/crypto/sasl.js#L24-L60","documentation":"Thrown during SCRAM authentication (sasl.js:41-43) when the PostgreSQL server's advertised SASL mechanism list does not include SCRAM-SHA-256 or SCRAM-SHA-256-PLUS. node-postgres only implements the SCRAM-SHA-256 family per RFC 5802/7677; older authentication methods (like SCRAM-SHA-512 or GSSAPI) are not supported. The candidates array is built dynamically: SCRAM-SHA-256-PLUS is added first if a TLS stream with channel-binding support is available, then SCRAM-SHA-256. If the server offers neither, authentication cannot proceed.","triggerScenarios":"Connecting to a PostgreSQL server configured with password_encryption=scram-sha-512-only or an older server (pre-10) that only offers MD5 or cleartext, but where the auth flow reaches the SASL handler. Also if a proxy or connection pooler (like PgBouncer in certain modes) strips or rewrites the mechanism list.","commonSituations":"PostgreSQL 18+ defaults to scram-sha-512; if the server is configured to only accept that, this client cannot authenticate. A misconfigured PgBouncer or a man-in-the-middle altering the auth negotiation. Connecting to a non-PostgreSQL server that speaks a different SASL dialect.","solutions":["Ensure the PostgreSQL server supports SCRAM-SHA-256 by setting password_encryption='scram-sha-256' in postgresql.conf and re-setting the user's password.","If connecting through PgBouncer, verify its auth configuration passes through SCRAM-SHA-256.","Upgrade node-postgres to the latest version; if your server only offers scram-sha-512, you may need a driver or server-side change to enable scram-sha-256."],"exampleFix":"-- on the PostgreSQL server\nALTER SYSTEM SET password_encryption = 'scram-sha-256';\nSELECT pg_reload_conf();\nALTER ROLE myuser WITH PASSWORD 'mypass'; -- re-hash with new scheme","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await client.connect();\n} catch (err) {\n  if (/Only mechanism.*SCRAM-SHA-256/i.test(err.message)) {\n    console.error('Server does not offer SCRAM-SHA-256. Check password_encryption on the server.');\n  }\n  throw err;\n}","preventionTips":["Ensure the PostgreSQL server has password_encryption='scram-sha-256' and roles are re-hashed.","If using PgBouncer, verify it is configured to pass SCRAM auth through (auth_type).","Keep node-postgres updated; newer versions may add support for additional SASL mechanisms."],"tags":["sasl","authentication","scram","security"],"analyzedSha":"c5e8c9a57bff6d9160ec5dbd5c4f4c1e4c460711","analyzedAt":"2026-08-03T18:47:28.334Z","schemaVersion":2}