{"record":{"id":"394d8b6f5b5e819d","repo":"denoland/deno","slug":"failed-to-get-ecdh-private-key","errorCode":null,"errorMessage":"Failed to get ECDH private key","messagePattern":"Failed to get ECDH private key","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/crypto/diffiehellman.ts","lineNumber":1515,"sourceCode":"    );\n    this.#pubbuf = pubbuf;\n    this.#privbuf = privbuf;\n\n    if (format === \"hybrid\") {\n      const compressedBuf = Buffer.from(op_node_ecdh_encode_pubkey(\n        this.#curve.name,\n        pubbuf,\n        true,\n      ));\n      pubbuf[0] = compressedBuf[0] + 4;\n    }\n\n    return ecdhEncode(pubbuf, encoding ?? \"buffer\");\n  }\n\n  getPrivateKey(encoding?: any): Buffer | string {\n    if (this.#privbuf === null) {\n      throw new Error(\"Failed to get ECDH private key\");\n    }\n    return ecdhEncode(this.#privbuf, encoding ?? \"buffer\");\n  }\n\n  getPublicKey(\n    encoding?: any,\n    format: any = \"uncompressed\",\n  ): Buffer | string {\n    if (this.#pubbuf === null) {\n      throw new Error(\"Failed to get ECDH public key\");\n    }\n    validateEcdhFormat(format);\n    const pubbuf = Buffer.from(op_node_ecdh_encode_pubkey(\n      this.#curve.name,\n      this.#pubbuf,\n      format === \"compressed\",\n    ));\n    if (format === \"hybrid\") {","sourceCodeStart":1497,"sourceCodeEnd":1533,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/crypto/diffiehellman.ts#L1497-L1533","documentation":"getPrivateKey() throws when the ECDH instance's private key buffer (#privbuf) is null. A fresh crypto.createECDH(curve) object holds only the curve choice; the private key exists only after generateKeys() or setPrivateKey() has run, and getPrivateKey() refuses to hand back nothing.","triggerScenarios":"const ecdh = crypto.createECDH('prime256v1'); ecdh.getPrivateKey(); with no prior generateKeys()/setPrivateKey(). Also after a failed setPrivateKey() that threw before assigning #privbuf.","commonSituations":"Serialization helpers that dump keys right after construction; refactors that move generateKeys() into a conditional branch that does not always execute; copying tutorial code that omitted the generateKeys step.","solutions":["Call ecdh.generateKeys() (or ecdh.setPrivateKey(priv)) before ecdh.getPrivateKey()","Initialize key material in the same function that creates the ECDH object so the two cannot be separated","Wrap key export in a helper that generates on first use if the private key is missing"],"exampleFix":"// before\nconst ecdh = crypto.createECDH('prime256v1');\nstore.save('priv', ecdh.getPrivateKey('hex'));\n\n// after\nconst ecdh = crypto.createECDH('prime256v1');\necdh.generateKeys();\nstore.save('priv', ecdh.getPrivateKey('hex'));","handlingStrategy":"validation","validationCode":"function exportPrivateKey(ecdh: crypto.ECDH, curve: string): string {\n  try {\n    return ecdh.getPrivateKey('hex');\n  } catch {\n    ecdh.generateKeys();\n    return ecdh.getPrivateKey('hex');\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Call generateKeys() in the same statement block as createECDH()","Keep key initialization and key export next to each other in code","Track initialization state in your own wrapper instead of relying on the error"],"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"}