denoland/deno · error · DOMException

Invalid key type

Error message

Invalid key type

What it means

_validateAsymmetricKeyAlgorithm throws DOMException DataError 'Invalid key type' when a KeyObject whose asymmetricKeyType is 'ed25519' or 'x25519' is converted via toCryptoKey() with an algorithm name that is not exactly 'Ed25519' or 'X25519' respectively. WebCrypto gives these curves dedicated algorithm names, separate from the ECDSA/ECDH named-curve namespace, and the polyfill enforces the 1:1 mapping.

Source

Thrown at ext/node/polyfills/internal/crypto/keys.ts:1036

    if (format === "pem") {
      return op_node_export_public_key_pem(this[kHandle], type);
    } else {
      return Buffer.from(op_node_export_public_key_der(this[kHandle], type));
    }
  }
}

function _validateAsymmetricKeyAlgorithm(
  keyObject: AsymmetricKeyObject,
  algName: string,
) {
  const keyType = keyObject.asymmetricKeyType;

  if (keyType === "ed25519" || keyType === "x25519") {
    const expectedAlg = keyType === "ed25519" ? "Ed25519" : "X25519";
    if (algName !== expectedAlg) {
      throw new DOMException("Invalid key type", "DataError");
    }
  } else if (keyType === "ed448" || keyType === "x448") {
    const expectedAlg = keyType === "ed448" ? "Ed448" : "X448";
    if (algName !== expectedAlg) {
      throw new DOMException("Invalid key type", "DataError");
    }
  }
}

function _validateEcNamedCurve(
  keyObject: AsymmetricKeyObject,
  algorithm: object,
) {
  const details = keyObject.asymmetricKeyDetails;
  const alg = algorithm as { namedCurve?: string };
  if (alg.namedCurve && details?.namedCurve) {
    const curveMap: Record<string, string> = {
      "prime256v1": "P-256",

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Match the algorithm name to the key type: ed25519 -> 'Ed25519', x25519 -> 'X25519'
  2. Derive the algorithm name from keyObject.asymmetricKeyType instead of hardcoding it
  3. If you intended ECDSA/ECDH with P-curves, generate an 'ec' key pair instead of an ed25519/x25519 one

Example fix

// before
const ck = privateKey.toCryptoKey('ECDSA', true, ['sign']); // key is ed25519 -> throws

// after
const name = privateKey.asymmetricKeyType === 'ed25519' ? 'Ed25519' : 'X25519';
const ck = privateKey.toCryptoKey(name, true, ['sign']);
Defensive patterns

Strategy: type-guard

Validate before calling

const ALG_BY_TYPE: Record<string, string> = {
  ed25519: 'Ed25519', x25519: 'X25519', ed448: 'Ed448', x448: 'X448',
};
const algName = typeof algorithm === 'string' ? algorithm : algorithm.name;
const expected = ALG_BY_TYPE[keyObject.asymmetricKeyType as string];
if (expected && algName !== expected) {
  algorithm = typeof algorithm === 'string' ? expected : { ...algorithm, name: expected };
}

Type guard

function algorithmMatchesKeyType(keyObject: KeyObject, algName: string): boolean {
  const t = keyObject.asymmetricKeyType;
  if (t === 'ed25519' || t === 'x25519' || t === 'ed448' || t === 'x448') {
    return algName.toLowerCase() === t; // 'Ed25519' vs 'ed25519'
  }
  return true; // other types are not checked here
}

Try / catch

try {
  ck = keyObject.toCryptoKey(algorithm, extractable, usages);
} catch (e) {
  if (e instanceof DOMException && e.name === 'DataError' && e.message === 'Invalid key type') {
    // re-derive the algorithm name from keyObject.asymmetricKeyType and retry
  } else throw e;
}

Prevention

When it happens

Trigger: generateKeyPairSync('ed25519').privateKey.toCryptoKey('ECDSA', true, ['sign']); or generateKeyPairSync('x25519').privateKey.toCryptoKey('Ed25519', true, []) — any keyType/algorithm-name mismatch in the Edwards/Montgomery family.

Common situations: Algorithm chosen from config while keys are generated elsewhere; generic sign/verify code that assumes ECDSA for every curve; confusing the signature curve (Ed25519) with the key-exchange curve (X25519) during JWT/EdDSA work.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/8e8f859a6e433656. Report an issue: GitHub.