mongodb/node-mongodb-native · error · MongoInvalidArgumentError

Username must be a string

Error message

Username must be a string

What it means

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.

Solutions

  1. Ensure username is a string when constructing credentials (the public API does this for you)
  2. If using the internal API, coerce username to string before it reaches SCRAM
  3. Prefer SCRAM-SHA-256 which uses saslprep instead of passwordDigest
  4. Report a driver bug if reached via the public API

Example fix

// before
const credentials = { username: undefined, password: 'x', mechanism: 'SCRAM-SHA-1' };

// after
const credentials = { username: 'appUser', password: 'x', mechanism: 'SCRAM-SHA-1' };
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof clientOptions.auth?.username !== 'string') {
  throw new TypeError('auth.username must be a string');
}

Type guard

function isStringUsername(auth: { username?: unknown }): auth is { username: string } {
  return typeof auth.username === 'string';
}

Try / catch

try {
  await client.connect();
} catch (err) {
  if (err instanceof MongoInvalidArgumentError && /Username must be a string/.test(err.message)) {
    // coerce/fix username and retry
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11). Data as JSON: /api/errors/c3f2effd2fe1d3dd. Report an issue: GitHub.

Appendix: source

Thrown at src/cmap/auth/scram.ts:219

  };

  await connection.command(ns(`${db}.$cmd`), retrySaslContinueCmd, undefined);
}

function parsePayload(payload: Binary) {
  const payloadStr = ByteUtils.toUTF8(payload.buffer, 0, payload.position, false);
  const dict: Document = {};
  const parts = payloadStr.split(',');
  for (let i = 0; i < parts.length; i++) {
    const valueParts = (parts[i].match(/^([^=]*)=(.*)$/) ?? []).slice(1);
    dict[valueParts[0]] = valueParts[1];
  }
  return dict;
}

function passwordDigest(username: string, password: string) {
  if (typeof username !== 'string') {
    throw new MongoInvalidArgumentError('Username must be a string');
  }

  if (typeof password !== 'string') {
    throw new MongoInvalidArgumentError('Password must be a string');
  }

  if (password.length === 0) {
    throw new MongoInvalidArgumentError('Password cannot be empty');
  }

  let nodeCrypto;
  try {
    // TODO: NODE-7424 - remove dependency on 'crypto' for SCRAM-SHA-1 authentication
    // eslint-disable-next-line @typescript-eslint/no-require-imports
    nodeCrypto = require('crypto');
  } catch (e) {
    throw new MongoRuntimeError(
      'Node.js crypto module is required for SCRAM-SHA-1 authentication',

View on GitHub (pinned to dce7939f86)