mongodb/node-mongodb-native · error · MongoCryptInvalidArgumentError

"options" cannot contain both "keyId" and "keyAltName"

Error message

"options" cannot contain both "keyId" and "keyAltName"

What it means

Thrown by ClientEncryption.encrypt (MongoCryptInvalidArgumentError) when both options.keyId and options.keyAltName are provided. Encryption must be keyed by exactly one identifier; specifying both is ambiguous and the driver refuses to guess which key to use.

Source

Thrown at src/client-side-encryption/client_encryption.ts:780

      algorithm,
      keyId,
      keyAltName,
      contentionFactor,
      queryType,
      rangeOptions,
      stringOptions,
      textOptions
    } = options;
    const contextOptions: ExplicitEncryptionContextOptions = {
      expressionMode,
      algorithm
    };
    if (keyId) {
      contextOptions.keyId = keyId.buffer;
    }
    if (keyAltName) {
      if (keyId) {
        throw new MongoCryptInvalidArgumentError(
          `"options" cannot contain both "keyId" and "keyAltName"`
        );
      }
      if (typeof keyAltName !== 'string') {
        throw new MongoCryptInvalidArgumentError(
          `"options.keyAltName" must be of type string, but was of type ${typeof keyAltName}`
        );
      }

      contextOptions.keyAltName = serialize({ keyAltName });
    }
    if (typeof contentionFactor === 'number' || typeof contentionFactor === 'bigint') {
      contextOptions.contentionFactor = contentionFactor;
    }
    if (typeof queryType === 'string') {
      contextOptions.queryType = queryType;
    }

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Pass exactly one of keyId or keyAltName.
  2. If you have both, prefer keyId (the explicit UUID) and drop keyAltName.
  3. Use a discriminated option builder that returns either { keyId } or { keyAltName } but never both.

Example fix

// before
await ce.encrypt(value, { keyId, keyAltName, algorithm });

// after
await ce.encrypt(value, { keyId, algorithm });
Defensive patterns

Strategy: validation

Validate before calling

function normalizeEncryptOpts(opt) {
  if (opt.keyId && opt.keyAltName)
    throw new Error('Pass exactly one of keyId or keyAltName');
  return opt;
}

Type guard

type EncryptKeyOption = { keyId: Binary; keyAltName?: undefined } | { keyId?: undefined; keyAltName: string };

Try / catch

try { await ce.encrypt(value, opt); }
catch (err) {
  if (err instanceof MongoCryptInvalidArgumentError && /cannot contain both/.test(err.message)) {
    /* drop keyAltName, keep keyId */
  } else throw err;
}

Prevention

When it happens

Trigger: Calling encrypt(value, { keyId: <binary>, keyAltName: 'myKey', algorithm: ... }); commonly happens when keyId defaults from a previous lookup and keyAltName is added for convenience.

Common situations: Refactoring encrypt calls to switch from keyId to keyAltName without removing the other; building options from a config that carries both fields; helper functions that always pass both.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04). Data as JSON: /data/errors/29d9d3152b2c2bcf.json. Report an issue: GitHub.