{"record":{"id":"c3f2effd2fe1d3dd","repo":"mongodb/node-mongodb-native","slug":"username-must-be-a-string","errorCode":null,"errorMessage":"Username must be a string","messagePattern":"Username must be a string","errorType":"exception","errorClass":"MongoInvalidArgumentError","httpStatus":null,"severity":"error","filePath":"src/cmap/auth/scram.ts","lineNumber":219,"sourceCode":"  };\n\n  await connection.command(ns(`${db}.$cmd`), retrySaslContinueCmd, undefined);\n}\n\nfunction parsePayload(payload: Binary) {\n  const payloadStr = ByteUtils.toUTF8(payload.buffer, 0, payload.position, false);\n  const dict: Document = {};\n  const parts = payloadStr.split(',');\n  for (let i = 0; i < parts.length; i++) {\n    const valueParts = (parts[i].match(/^([^=]*)=(.*)$/) ?? []).slice(1);\n    dict[valueParts[0]] = valueParts[1];\n  }\n  return dict;\n}\n\nfunction passwordDigest(username: string, password: string) {\n  if (typeof username !== 'string') {\n    throw new MongoInvalidArgumentError('Username must be a string');\n  }\n\n  if (typeof password !== 'string') {\n    throw new MongoInvalidArgumentError('Password must be a string');\n  }\n\n  if (password.length === 0) {\n    throw new MongoInvalidArgumentError('Password cannot be empty');\n  }\n\n  let nodeCrypto;\n  try {\n    // TODO: NODE-7424 - remove dependency on 'crypto' for SCRAM-SHA-1 authentication\n    // eslint-disable-next-line @typescript-eslint/no-require-imports\n    nodeCrypto = require('crypto');\n  } catch (e) {\n    throw new MongoRuntimeError(\n      'Node.js crypto module is required for SCRAM-SHA-1 authentication',","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/cmap/auth/scram.ts#L201-L237","documentation":"Thrown by passwordDigest (scram.ts:219) when the username passed to it is not a string. passwordDigest builds the SCRAM-SHA-1 MD5 digest from `${username}:mongo:${password}`, so a non-string username (undefined, number, object) cannot be hashed. Raised as MongoInvalidArgumentError. This guard is internal; the public API normalizes credentials to strings upstream.","triggerScenarios":"passwordDigest is invoked (only on the SCRAM-SHA-1 path, scram.ts:136) with a username that is not a string. Reachable if credentials.username is undefined/null/non-string when SCRAM-SHA-1 runs, which the credential-parsing layer normally prevents.","commonSituations":"A driver regression or fork where credentials.username is not coerced to a string before SCRAM-SHA-1 auth. Programmatic construction of MongoCredentials with a non-string username. A test that bypasses credential parsing.","solutions":["Ensure username is a string when constructing credentials (the public API does this for you)","If using the internal API, coerce username to string before it reaches SCRAM","Prefer SCRAM-SHA-256 which uses saslprep instead of passwordDigest","Report a driver bug if reached via the public API"],"exampleFix":"// before\nconst credentials = { username: undefined, password: 'x', mechanism: 'SCRAM-SHA-1' };\n\n// after\nconst credentials = { username: 'appUser', password: 'x', mechanism: 'SCRAM-SHA-1' };","handlingStrategy":"type-guard","validationCode":"if (typeof clientOptions.auth?.username !== 'string') {\n  throw new TypeError('auth.username must be a string');\n}","typeGuard":"function isStringUsername(auth: { username?: unknown }): auth is { username: string } {\n  return typeof auth.username === 'string';\n}","tryCatchPattern":"try {\n  await client.connect();\n} catch (err) {\n  if (err instanceof MongoInvalidArgumentError && /Username must be a string/.test(err.message)) {\n    // coerce/fix username and retry\n  } else throw err;\n}","preventionTips":["Always pass string credentials via the public MongoClient options","Validate auth.username is a string at config-load time","Prefer SCRAM-SHA-256, which does not route through passwordDigest"],"tags":["scram","types","internal","authentication"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}