denoland/deno · error · ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY

ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY

ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY

Error message

Public key is not valid for specified curve

What it means

computeSecret() on an ECDH instance throws ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY when the instance's private key (#privbuf) is null — that is, the shared-secret computation cannot even start because this side has no private key. Despite the name, nothing about the peer's public key has been checked yet; the error fires before the op runs.

Source

Thrown at ext/node/polyfills/internal/crypto/diffiehellman.ts:1449

      // compressed first byte is 02 (even) or 03 (odd)
      // hybrid first byte is 06 (even) or 07 (odd)
      result[0] = compressedBuf[0] + 4;
    }

    if (outputEncoding && outputEncoding !== "buffer") {
      // deno-lint-ignore deno-internal/prefer-primordials -- Buffer.prototype.toString(encoding) has no primordial
      return result.toString(outputEncoding);
    }
    return result;
  }

  computeSecret(
    otherPublicKey: ArrayBufferView | string,
    inputEncoding?: any,
    outputEncoding?: any,
  ): Buffer | string {
    if (this.#privbuf === null) {
      throw new ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY();
    }

    let otherBuf: Buffer;
    if (typeof otherPublicKey === "string") {
      otherBuf = Buffer.from(otherPublicKey, inputEncoding);
    } else {
      const parts = getViewParts(otherPublicKey);
      otherBuf = Buffer.from(parts.ab, parts.off, parts.len);
    }

    const secretBuf = Buffer.alloc(this.#curve.sharedSecretSize);

    try {
      op_node_ecdh_compute_secret(
        this.#curve.name,
        this.#privbuf,
        this.#pubbuf,
        otherBuf,

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Call ecdh.generateKeys() before computeSecret() when you are generating a new key pair
  2. If you already have a private key, call ecdh.setPrivateKey(priv) — it derives the public key automatically
  3. If migrating legacy setPublicKey-based code, replace it: set both keys via setPrivateKey, or generate fresh keys and exchange them

Example fix

// before
const ecdh = crypto.createECDH('prime256v1');
ecdh.setPublicKey(theirPub);
const secret = ecdh.computeSecret(peerPub);

// after
const ecdh = crypto.createECDH('prime256v1');
ecdh.setPrivateKey(myPriv);
const secret = ecdh.computeSecret(peerPub);
Defensive patterns

Strategy: validation

Validate before calling

// createECDH objects expose no key until generated; initialize eagerly.
function makeEcdh(curve: string, priv?: Buffer) {
  const ecdh = crypto.createECDH(curve);
  if (priv) ecdh.setPrivateKey(priv); else ecdh.generateKeys();
  return ecdh; // privbuf is guaranteed non-null
}
const secret = makeEcdh('prime256v1').computeSecret(peerPub);

Try / catch

catch (e) { if ((e as NodeJS.ErrnoException).code === 'ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY' && !keysInitialized) { /* initialize keys and retry once */ } throw e; }

Prevention

When it happens

Trigger: const ecdh = crypto.createECDH('prime256v1'); ecdh.computeSecret(peerPub); — generateKeys() or setPrivateKey() was never called. Calling setPublicKey() alone does not help: it sets #pubbuf but leaves #privbuf null.

Common situations: Old Node.js examples that used the (deprecated) setPublicKey flow to import a key pair; stateful servers that reuse an ECDH object after a reset; forgetting that a fresh createECDH() object has no key material until generateKeys() runs.

Related errors


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