denoland/deno · error · TypeError

Invalid key type

Error message

Invalid key type

What it means

prepareKey (cipher.ts:911) throws this TypeError when the key argument is an options object ({ key, encoding, passphrase, format }) but the nested key value is neither string nor binary data. KeyObjects of type 'public'/'private', and { format: 'jwk' } payloads, are handled earlier, so this fires for objects whose key field is the wrong thing — including secret-type KeyObjects, which do not match the public/private branches.

Source

Thrown at ext/node/polyfills/internal/crypto/cipher.ts:911

    const data = key.export({ type: "pkcs8", format: "pem" });
    return { data: getArrayBufferOrView(data, "key") };
  } else if (typeof key == "object") {
    const { key: data, encoding, passphrase, format, type } = key;
    if (isKeyObject(data)) {
      return prepareKey(data);
    }
    if (format === "jwk") {
      // Build a KeyObject from the JWK and export it as PEM so the
      // downstream op can consume it via the existing PEM parsing path.
      const isPrivate = typeof data === "object" && data !== null &&
        typeof (data as { d?: unknown }).d === "string";
      const keyObject = isPrivate
        ? createPrivateKey({ key: data, format: "jwk" })
        : createPublicKey({ key: data, format: "jwk" });
      return prepareKey(keyObject);
    }
    if (!isStringOrBuffer(data)) {
      throw new TypeError("Invalid key type");
    }

    // If a passphrase is supplied with raw key material, decrypt the key via
    // the native key handle and re-export as unencrypted PKCS#8 PEM so the
    // downstream RSA ops can parse it.
    if (passphrase != null) {
      const keyFormat = format ?? (typeof data === "string" ? "pem" : "der");
      const keyData = getArrayBufferOrView(data, "key", encoding);
      const passphraseData = getArrayBufferOrView(passphrase, "passphrase");
      const handle = op_node_create_private_key(
        keyData,
        keyFormat,
        type ?? "",
        passphraseData,
      );
      const pem = op_node_export_private_key_pem(
        handle,
        "pkcs8",

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pass the PEM string or DER Buffer directly, or a KeyObject from createPublicKey/createPrivateKey
  2. Unwrap nested structures so options.key is the raw key material itself
  3. For JWK input set format: 'jwk' so the dedicated branch runs
  4. Never feed secret-type KeyObjects to the RSA encrypt/decrypt functions

Example fix

// before
publicEncrypt({ key: { pem: pemString } }, data); // Invalid key type

// after
publicEncrypt(pemString, data);
// or
publicEncrypt(createPublicKey(pemString), data);
Defensive patterns

Strategy: type-guard

Validate before calling

import { isKeyObject } from 'node:crypto';
function isRawKeyMaterial(v) {
  return typeof v === 'string' || ArrayBuffer.isView(v) || v instanceof ArrayBuffer;
}
function assertPrepareable(key) {
  if (isRawKeyMaterial(key) || isKeyObject(key)) return;
  if (key && typeof key === 'object') {
    if (isKeyObject(key.key) || key.format === 'jwk' || isRawKeyMaterial(key.key)) return;
  }
  throw new TypeError('Invalid key type');
}

Type guard

function isAcceptableKeyArg(k) {
  if (typeof k === 'string' || ArrayBuffer.isView(k) || k instanceof ArrayBuffer) return true;
  if (isKeyObject(k) && (k.type === 'public' || k.type === 'private')) return true;
  if (k && typeof k === 'object') {
    return isKeyObject(k.key) || k.format === 'jwk' || typeof k.key === 'string' || ArrayBuffer.isView(k.key);
  }
  return false;
}

Prevention

When it happens

Trigger: publicEncrypt({ key: 123 }, data); publicEncrypt({ key: { pem } }, data) — double-wrapped options; passing a secret KeyObject from createSecretKey() (only 'public'/'private' types are recognized at the top level, and the object branch then finds no usable .key field); a parsed JSON document passed instead of its string field.

Common situations: createSecretKey bytes reused for RSA operations; KMS/JWKS wrappers not unwrapped before use; variable naming where `key` accidentally holds a container rather than the material.

Related errors


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