mongodb/node-mongodb-native · error · MongoCryptInvalidArgumentError

"options.keyAltName" must be of type string, but was of type

Error message

"options.keyAltName" must be of type string, but was of type ${typeof keyAltName}

What it means

Thrown by ClientEncryption.encrypt (MongoCryptInvalidArgumentError) when options.keyAltName is provided but is not a string. keyAltName is serialized as a BSON string key, so a non-string value (number, object, null) is rejected before reaching libmongocrypt.

Source

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

      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;
    }

    if (typeof rangeOptions === 'object') {
      contextOptions.rangeOptions = serialize(rangeOptions);
    }

    const resolvedStringOptions = stringOptions ?? textOptions;

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Ensure keyAltName is a string alias previously registered via createDataKey.
  2. If you have a UUID, use keyId (Binary) instead of keyAltName.
  3. Add a runtime type check `typeof keyAltName === 'string'` before calling encrypt when values come from untyped sources.

Example fix

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

// after
await ce.encrypt(value, { keyId: new Binary(keyIdUuid, 4), algorithm });
// or, if alias:
await ce.encrypt(value, { keyAltName: 'myKeyAlias', algorithm });
Defensive patterns

Strategy: type-guard

Validate before calling

function requireStringKeyAltName(opt) {
  if ('keyAltName' in opt && typeof opt.keyAltName !== 'string')
    throw new TypeError('keyAltName must be a string');
  return opt;
}

Type guard

function isStringKeyAltName(opt: any): opt is { keyAltName: string; keyId?: undefined } {
  return 'keyAltName' in opt && typeof opt.keyAltName === 'string';
}

Try / catch

try { await ce.encrypt(value, opt); }
catch (err) {
  if (err instanceof MongoCryptInvalidArgumentError && /keyAltName" must be of type string/.test(err.message)) {
    /* if you have a UUID, switch to keyId; otherwise pass a string alias */
  } else throw err;
}

Prevention

When it happens

Trigger: Calling encrypt(value, { keyAltName: 123, algorithm }) or keyAltName: undefined-but-truthy; passing an object intended as a masterKey in the wrong field.

Common situations: TypeScript types bypassed with `as any`; building keyAltName from numeric IDs; confusing keyAltName with keyId (UUID/Binary).

Related errors


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