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
- Pass exactly one of keyId or keyAltName.
- If you have both, prefer keyId (the explicit UUID) and drop keyAltName.
- 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
- Model encrypt options as a discriminated union.
- Default to keyId when you have a UUID; reserve keyAltName for named aliases only.
- Code-review helper functions that assemble encrypt options.
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
- "options.keyAltName" must be of type string, but was of type
- Missing required option `keyVaultNamespace`
- Option "keyAltNames" must be an array of strings, but was of
- Option "keyAltNames" must be an array of strings, but item a
- Cannot set both proxyOptions and kmsConnectCallback
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/29d9d3152b2c2bcf.json.
Report an issue: GitHub.