Error message
Invalid key object type public, expected private.
The two nouns swap with the operation: verify() with a private-only input reports "expected private or public", sign() with a secret reports the secret variant. The structure of the message is stable.
Node.js crypto — TypeError, code ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE
What it means
You passed a KeyObject of the wrong class for the operation: crypto.sign() needs a private key but received a public one (or verify() received a secret key, etc.). Node's key objects know their own type — public, private or secret — and each API accepts specific types only.
Why it happens
Swapped variables at the call site
commonpublicKey and privateKey exchanged in a destructuring, or a function parameter named key receiving whichever the caller had. Signing with the public key is impossible by construction, and Node says so instead of failing mysteriously later.
Loading produced a different type than assumed
commoncreatePublicKey(privatePem) intentionally derives a public key — code that then treats the result as a private key for signing fails here. Similarly, a PEM file that actually contains a public key loads as type "public" no matter what the filename says.
Secret (symmetric) key in an asymmetric API
occasionalcreateSecretKey() output (an HMAC/AES key) handed to sign/verify for ECDSA. Symmetric material cannot participate in public-key signatures.
How to fix it
- 1.
Assert key types at the boundary
KeyObject.type is "public" | "private" | "secret". A one-line assertion converts a confusing crypto error into an obvious one at load time.
js import { createPrivateKey } from "node:crypto"; const signingKey = createPrivateKey(pem); if (signingKey.type !== "private") { throw new Error(`expected private key, got ${signingKey.type}`); } - 2.
Use each half of the pair for its own operation
Private signs, public verifies. If you only hold a private key, derive the public half for verification instead of reusing the private object everywhere.
js import { createPublicKey, sign, verify } from "node:crypto"; const signature = sign("sha256", data, privateKey); // private → sign const publicKey = createPublicKey(privateKey); // derive public half const ok = verify("sha256", data, publicKey, signature); // public → verify