denoland/deno · error · Error

invalid curve

Error message

invalid curve

What it means

The ECDH constructor (diffiehellman.ts:1381) looks the curve up by exact name in the built-in elliptic curve list — the same names crypto.getCurves() returns (OpenSSL-style). A miss throws the plain Error 'invalid curve'. WebCrypto-style names like 'P-256' do not match; the OpenSSL name for that curve is 'prime256v1'.

Source

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

): Buffer | string {
  if (encoding === undefined || encoding === "buffer") {
    return buffer;
  }
  // deno-lint-ignore deno-internal/prefer-primordials -- Buffer.prototype.toString(encoding) has no primordial
  return buffer.toString(encoding);
}

class ECDHImpl {
  #curve: any; // the selected curve
  #privbuf: Buffer | null = null; // the private key
  #pubbuf: Buffer | null = null; // the public key

  constructor(curve: string) {
    validateString(curve, "curve");

    const c = ArrayPrototypeFind(ellipticCurves, (x) => x.name == curve);
    if (c == undefined) {
      throw new Error("invalid curve");
    }

    this.#curve = c;
  }

  static convertKey(
    key: any,
    curve: string,
    inputEncoding?: any,
    outputEncoding?: any,
    format?: any,
  ): Buffer | string {
    validateString(curve, "curve");
    const buf = getArrayBufferOrView(key, "key", inputEncoding);

    let compress: boolean;
    if (format) {
      if (format === "compressed") {

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Use OpenSSL-style names: 'prime256v1' (P-256), 'secp384r1' (P-384), 'secp521r1' (P-521), 'secp256k1'
  2. Check membership with crypto.getCurves().includes(curve) before constructing
  3. Translate WebCrypto names once at the edge: P-256 -> prime256v1, P-384 -> secp384r1, P-521 -> secp521r1
  4. For X25519/X448, use crypto.diffieHellman({ privateKey, publicKey }) with KeyObjects instead of ECDH

Example fix

// before
const ecdh = createECDH('P-256'); // invalid curve

// after
const ecdh = createECDH('prime256v1'); // same curve, OpenSSL name
Defensive patterns

Strategy: validation

Validate before calling

import { getCurves } from 'node:crypto';
const WEBCRYPTO_TO_OPENSSL = { 'P-256': 'prime256v1', 'P-384': 'secp384r1', 'P-521': 'secp521r1' };
function normalizeCurveName(c) {
  const n = WEBCRYPTO_TO_OPENSSL[c] ?? c;
  if (!getCurves().includes(n)) throw new RangeError(`unsupported curve: ${c}`);
  return n;
}

Type guard

import { getCurves } from 'node:crypto';
function isSupportedCurve(c) { return getCurves().includes(c); }

Try / catch

try { ecdh = createECDH(curve); } catch (e) { if (e.message === 'invalid curve') { throw new Error(`curve '${curve}' not supported; see crypto.getCurves()`); } else throw e; }

Prevention

When it happens

Trigger: new ECDH('P-256') or createECDH('P-384') — WebCrypto/JWS names; typos like 'secp233k1'; 'curve25519'/'x25519' which are not ECDH curves here (X25519 goes through crypto.diffieHellman with KeyObjects); names from other stacks like 'NIST P-256'.

Common situations: Porting WebCrypto/JWT (ES256) code that uses 'P-256'; curve names pulled from RFC/JOSE registries; stale docs or renamed curves in newer OpenSSL versions.

Related errors


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