{"record":{"id":"ad53972f11229f9e","repo":"mongodb/node-mongodb-native","slug":"unable-to-continue-scram-without-valid-nonce","errorCode":null,"errorMessage":"Unable to continue SCRAM without valid nonce","messagePattern":"Unable to continue SCRAM without valid nonce","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/cmap/auth/scram.ts","lineNumber":127,"sourceCode":"  const db = credentials.source;\n\n  const saslStartCmd = makeFirstMessage(cryptoMethod, credentials, nonce);\n  const response = await connection.command(ns(`${db}.$cmd`), saslStartCmd, undefined);\n  await continueScramConversation(cryptoMethod, response, authContext);\n}\n\nasync function continueScramConversation(\n  cryptoMethod: CryptoMethod,\n  response: Document,\n  authContext: AuthContext\n): Promise<void> {\n  const connection = authContext.connection;\n  const credentials = authContext.credentials;\n  if (!credentials) {\n    throw new MongoMissingCredentialsError('AuthContext must provide credentials.');\n  }\n  if (!authContext.nonce) {\n    throw new MongoInvalidArgumentError('Unable to continue SCRAM without valid nonce');\n  }\n  const nonce = authContext.nonce;\n\n  const db = credentials.source;\n  const username = cleanUsername(credentials.username);\n  const password = credentials.password;\n\n  const processedPassword =\n    cryptoMethod === 'sha256' ? saslprep(password) : passwordDigest(username, password);\n\n  const payload: Binary = ByteUtils.isUint8Array(response.payload)\n    ? new Binary(response.payload)\n    : response.payload;\n\n  const dict = parsePayload(payload);\n\n  const iterations = parseInt(dict.i, 10);\n  if (iterations && iterations < 4096) {","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/cmap/auth/scram.ts#L109-L145","documentation":"Thrown by continueScramConversation (scram.ts:127) when authContext.nonce is unset while attempting the second SASL round. The nonce is generated in prepare() and must persist on the context for the proof computation; reaching this throw indicates the context lost its nonce or auth ran without prepare. Raised as MongoInvalidArgumentError.","triggerScenarios":"Entering continueScramConversation (via speculative response handling or executeScram) when authContext.nonce was never set or was cleared. Mirrors the executeScram nonce invariant (scram.ts:106) but on the conversation-continuation path.","commonSituations":"A driver regression where the nonce is not retained across the speculative-to-continue transition. Forked auth providers that reset the context. Re-authentication after pool reset.","solutions":["Report a driver bug if reached via the public API with reproduction steps","If using the internal API, ensure prepare() runs first so authContext.nonce is set","Upgrade the driver to pick up any nonce-retention fix"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await client.connect();\n} catch (err) {\n  if (err instanceof MongoInvalidArgumentError && /nonce/.test(err.message)) {\n    // internal invariant on the conversation path; report with topology/repro details\n    reportDriverBug(err);\n  }\n  throw err;\n}","preventionTips":["Avoid invoking internal auth provider methods directly","If forking, preserve authContext.nonce across prepare/auth transitions","Upgrade the driver to benefit from handshake/failover fixes"],"tags":["scram","internal","invariant","authentication"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}