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 Client-Side Field-Level Encryption (CSFLE) explicit encryption when both options.keyId and options.keyAltName are supplied to ClientEncryption.encrypt / encryptExpression. The driver passes key identification to libmongocrypt via exactly one of these two fields; specifying both is contradictory. It surfaces as a MongoCryptInvalidArgumentError and fails synchronously before any crypto operation runs.
Solutions
- Provide exactly one of options.keyId (the UUID Binary of the data encryption key) or options.keyAltName (the alternate name string) — never both.
- Audit the options object right before the encrypt call and delete the unused field: if you resolved a keyId, delete options.keyAltName.
- If you need deterministic key selection, store/retrieve a single key by keyAltName via getKeyByAltName and pass only its _id as keyId.
Example fix
// before
await clientEncryption.encrypt(value, {
algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-RANDOM',
keyId: dataKey._id,
keyAltName: 'customerKey' // throws: both set
});
// after
await clientEncryption.encrypt(value, {
algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-RANDOM',
keyId: dataKey._id
}); Defensive patterns
Strategy: validation
Validate before calling
function assertEncryptKeyOptions(options) {
const hasId = options.keyId != null;
const hasAlt = options.keyAltName != null;
if (hasId && hasAlt) {
throw new Error('Provide exactly one of options.keyId or options.keyAltName, not both.');
}
if (!hasId && !hasAlt) {
throw new Error('One of options.keyId or options.keyAltName is required.');
}
}
// call before clientEncryption.encrypt(...)
assertEncryptKeyOptions(options); Type guard
function isKeyAltNameString(v: unknown): v is string {
return v == null || typeof v === 'string';
} Try / catch
try {
await clientEncryption.encrypt(value, options);
} catch (e) {
if (e instanceof MongoCryptInvalidArgumentError && /both "keyId" and "keyAltName"/.test(e.message)) {
// fix the options and retry with one key identifier
}
throw e;
} Prevention
- Centralise encrypt-option construction in one helper that enforces the keyId XOR keyAltName rule.
- When migrating from keyAltName to keyId, delete the old field rather than leaving it.
When it happens
Trigger: Calling clientEncryption.encrypt(value, { keyId: <Binary>, keyAltName: 'name', algorithm: ... }) with both fields set; or building an options object programmatically and accidentally merging a keyId into an object that already carries keyAltName.
Common situations: Copying an options object that already had keyAltName and then adding keyId (or vice versa); migrating from keyAltName-based key lookup to keyId-based lookup and forgetting to delete the old field; spreading defaults `{ keyAltName: 'default' }` into an encrypt call that also sets keyId.
Related errors
- Missing required option `keyVaultNamespace`
- Option "autoEncryption" must be specified
- "options.keyAltName" must be of type string, but was of type
- Auth mechanism property ALLOWED_HOSTS must be an array of…
- Auto-encryption requested, but the module is not installed…
AI-assisted analysis of mongodb/node-mongodb-native@dce7939f86 (2026-08-11).
Data as JSON: /api/errors/29d9d3152b2c2bcf.
Report an issue: GitHub.
Appendix: 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 dce7939f86)