denoland/deno · error · ERR_CRYPTO_INCOMPATIBLE_KEY
ERR_CRYPTO_INCOMPATIBLE_KEY
ERR_CRYPTO_INCOMPATIBLE_KEY
Error message
Incompatible key types for Diffie-Hellman: ${privType} and ${pubType} What it means
statelessDH() — the engine behind crypto.diffieHellman({privateKey, publicKey}) — throws ERR_CRYPTO_INCOMPATIBLE_KEY when both KeyObjects have a known asymmetricKeyType and the types differ. Diffie-Hellman can only combine two keys of the same algorithm (e.g. 'ec' with 'ec', 'x25519' with 'x25519'); mixing kinds can never produce a shared secret.
Source
Thrown at ext/node/polyfills/internal/crypto/diffiehellman.ts:1607
ECDH.prototype.setPublicKey = deprecate(
ECDHImpl.prototype.setPublicKey,
"ecdh.setPublicKey() is deprecated.",
"DEP0031",
);
function statelessDH(
privateKeyObject: KeyObject,
publicKeyObject: KeyObject,
): Buffer {
const privateKey = getKeyObjectHandle(privateKeyObject, kConsumePrivate);
const publicKey = getKeyObjectHandle(publicKeyObject, kConsumePublic);
const privType = privateKeyObject.asymmetricKeyType;
const pubType = publicKeyObject.asymmetricKeyType;
if (
privType !== undefined && pubType !== undefined && privType !== pubType
) {
throw new ERR_CRYPTO_INCOMPATIBLE_KEY(
"key types for Diffie-Hellman",
`${privType} and ${pubType}`,
);
}
try {
const bytes = op_node_diffie_hellman(privateKey, publicKey);
return Buffer.from(bytes);
} catch (err) {
const e = err as Error & { code?: string };
if (e && typeof e.message === "string") {
if (
StringPrototypeIncludes(e.message, "mismatching domain parameters")
) {
e.code = "ERR_OSSL_MISMATCHING_DOMAIN_PARAMETERS";
} else if (
StringPrototypeIncludes(e.message, "failed during derivation")
) {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Use a matching pair: generate one key pair (e.g. generateKeyPairSync('x25519')) and pass its privateKey plus the peer's same-type public key
- Log privateKeyObject.asymmetricKeyType and publicKeyObject.asymmetricKeyType before the call and fix whichever side is wrong
- Verify PEM/DER files were loaded with createPrivateKey/createPublicKey and not swapped
Example fix
// before
const secret = crypto.diffieHellman({ privateKey: rsaPriv, publicKey: ecPub });
// after
const secret = crypto.diffieHellman({ privateKey: ecPriv, publicKey: ecPub }); Defensive patterns
Strategy: type-guard
Validate before calling
if (privateKeyObject.asymmetricKeyType !== publicKeyObject.asymmetricKeyType) {
throw new TypeError(
`key types must match: ${privateKeyObject.asymmetricKeyType} vs ${publicKeyObject.asymmetricKeyType}`,
);
}
const secret = crypto.diffieHellman({ privateKey: privateKeyObject, publicKey: publicKeyObject }); Type guard
const isMatchingDHPair = (priv: crypto.KeyObject, pub: crypto.KeyObject): boolean => priv.asymmetricKeyType === pub.asymmetricKeyType && ['ec', 'x25519', 'ed25519', 'dh'].includes(String(priv.asymmetricKeyType));
Try / catch
catch (e) { if ((e as NodeJS.ErrnoException).code === 'ERR_CRYPTO_INCOMPATIBLE_KEY') { /* log both key types, re-key the offending side */ } throw e; } Prevention
- Always generate a fresh pair with generateKeyPairSync and pass its private half plus the peer's same-type public half
- Log asymmetricKeyType when loading keys so mismatches are visible before the op
- Version your protocol's key algorithm so both sides agree after upgrades
When it happens
Trigger: crypto.diffieHellman({ privateKey: createPrivateKey(rsaPem), publicKey: createPublicKey(ecPem) }); or an 'x25519' private key with an 'ec' (NIST) public key, or 'dh' with 'ec'.
Common situations: Key-management code that grabs whatever KeyObject is at hand; protocols that upgraded one side from RSA/ECDH to X25519 while the other side still sends the old key type; config files pointing privateKey and publicKey at PEMs of different algorithms.
Related errors
- ERR_INVALID_ARG_VALUE
- ERR_INCOMPATIBLE_OPTION_PAIR
- ERR_CRYPTO_UNKNOWN_DH_GROUP
- ERR_MISSING_OPTION
- ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/459f2fa2822aac90.
Report an issue: GitHub.