{"record":{"id":"840749b3f87aae6c","repo":"denoland/deno","slug":"err-crypto-ecdh-invalid-public-key","errorCode":"ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY","errorMessage":"Public key is not valid for specified curve","messagePattern":"Public key is not valid for specified curve","errorType":"exception","errorClass":"ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/crypto/diffiehellman.ts","lineNumber":1449,"sourceCode":"      // compressed first byte is 02 (even) or 03 (odd)\n      // hybrid first byte is 06 (even) or 07 (odd)\n      result[0] = compressedBuf[0] + 4;\n    }\n\n    if (outputEncoding && outputEncoding !== \"buffer\") {\n      // deno-lint-ignore deno-internal/prefer-primordials -- Buffer.prototype.toString(encoding) has no primordial\n      return result.toString(outputEncoding);\n    }\n    return result;\n  }\n\n  computeSecret(\n    otherPublicKey: ArrayBufferView | string,\n    inputEncoding?: any,\n    outputEncoding?: any,\n  ): Buffer | string {\n    if (this.#privbuf === null) {\n      throw new ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY();\n    }\n\n    let otherBuf: Buffer;\n    if (typeof otherPublicKey === \"string\") {\n      otherBuf = Buffer.from(otherPublicKey, inputEncoding);\n    } else {\n      const parts = getViewParts(otherPublicKey);\n      otherBuf = Buffer.from(parts.ab, parts.off, parts.len);\n    }\n\n    const secretBuf = Buffer.alloc(this.#curve.sharedSecretSize);\n\n    try {\n      op_node_ecdh_compute_secret(\n        this.#curve.name,\n        this.#privbuf,\n        this.#pubbuf,\n        otherBuf,","sourceCodeStart":1431,"sourceCodeEnd":1467,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/crypto/diffiehellman.ts#L1431-L1467","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Call ecdh.generateKeys() before computeSecret() when you are generating a new key pair","If you already have a private key, call ecdh.setPrivateKey(priv) — it derives the public key automatically","If migrating legacy setPublicKey-based code, replace it: set both keys via setPrivateKey, or generate fresh keys and exchange them"],"exampleFix":"// before\nconst ecdh = crypto.createECDH('prime256v1');\necdh.setPublicKey(theirPub);\nconst secret = ecdh.computeSecret(peerPub);\n\n// after\nconst ecdh = crypto.createECDH('prime256v1');\necdh.setPrivateKey(myPriv);\nconst secret = ecdh.computeSecret(peerPub);","handlingStrategy":"validation","validationCode":"// createECDH objects expose no key until generated; initialize eagerly.\nfunction makeEcdh(curve: string, priv?: Buffer) {\n  const ecdh = crypto.createECDH(curve);\n  if (priv) ecdh.setPrivateKey(priv); else ecdh.generateKeys();\n  return ecdh; // privbuf is guaranteed non-null\n}\nconst secret = makeEcdh('prime256v1').computeSecret(peerPub);","typeGuard":null,"tryCatchPattern":"catch (e) { if ((e as NodeJS.ErrnoException).code === 'ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY' && !keysInitialized) { /* initialize keys and retry once */ } throw e; }","preventionTips":["Never hand out a createECDH() result without first calling generateKeys() or setPrivateKey()","Encapsulate ECDH construction in a factory that guarantees key state","Drop setPublicKey-based legacy flows; setPrivateKey derives the public key"],"tags":["crypto","ecdh","key-management","node-compat"],"backgroundTag":"ecdh-missing-private-key","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}