denoland/deno · error · TypeError

ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE

ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE

Error message

Invalid key object type ${key.type}, expected private.

What it means

getKeyObjectHandle validates a KeyObject against the operation context. For contexts that require a private key — kConsumePrivate (crypto.sign, the private side of DiffieHellman) and kCreatePublic (crypto.createPublicKey) — a KeyObject whose type is not 'private' throws ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE reporting the actual type and 'expected private'.

Source

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

    // @ts-expect-error __proto__ is magic
    __proto__: null,
    configurable: true,
    value: "KeyObject",
  },
});

function getKeyObjectHandle(key: KeyObject, ctx: number) {
  if (ctx === kCreatePrivate) {
    throw new ERR_INVALID_ARG_TYPE(
      "key",
      ["string", "ArrayBuffer", "Buffer", "TypedArray", "DataView"],
      key,
    );
  }

  if (key.type !== "private") {
    if (ctx === kConsumePrivate || ctx === kCreatePublic) {
      throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, "private");
    }
    if (key.type !== "public") {
      throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(
        key.type,
        "private or public",
      );
    }
  }

  return key[kHandle];
}

function getKeyObjectHandleFromJwk(key, ctx) {
  validateObject(key, "key");
  validateOneOf(
    key.kty,
    "key.kty",
    ["RSA", "EC", "OKP"],

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pass the private KeyObject to sign/derive operations; check key.type === 'private' when arguments come from elsewhere
  2. For createPublicKey on a KeyObject, use the existing public KeyObject directly instead of re-wrapping
  3. In shared helpers, branch on the input being a KeyObject vs raw PEM before calling factories

Example fix

// before
const sig = crypto.sign(null, data, publicKeyObject);
// after
const sig = crypto.sign(null, data, privateKeyObject);
Defensive patterns

Strategy: validation

Validate before calling

function requirePrivateKey(key) {
  if (!crypto.isKeyObject(key) || key.type !== 'private') {
    throw new Error(`Expected private KeyObject, got ${key?.type ?? typeof key}`);
  }
  return key;
}
crypto.sign(null, data, requirePrivateKey(signingKey));

Type guard

function isPrivateKeyObject(k) {
  return crypto.isKeyObject(k) && k.type === 'private';
}

Try / catch

try {
  return crypto.sign(null, data, key);
} catch (e) {
  if (e.code === 'ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE') throw new Error(`Wrong key kind for this op: ${e.message}`);
  throw e;
}

Prevention

When it happens

Trigger: crypto.sign(null, data, publicKeyObject); dh.computeSecret(publicKeyObject, privateKeyObject) with the arguments swapped; crypto.createPublicKey(publicKeyObject) — Deno throws where Node tolerantly returns the same key.

Common situations: Swapped arguments in diffiehellman.computeSecret; signing with the public key of a pair (PEM mix-ups); re-wrapping a public KeyObject via createPublicKey, a pattern that works on Node but not in the polyfill.

Related errors


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