denoland/deno · error · ERR_CRYPTO_ECDH_INVALID_FORMAT

ERR_CRYPTO_ECDH_INVALID_FORMAT

ERR_CRYPTO_ECDH_INVALID_FORMAT

Error message

Invalid ECDH format: ${format}

What it means

validateEcdhFormat (diffiehellman.ts:1356) validates the point-format parameter used by ECDH's getPublicKey and convertKey. Only 'compressed', 'uncompressed' and 'hybrid' are accepted; anything else throws ERR_CRYPTO_ECDH_INVALID_FORMAT naming the rejected value. Output encodings ('base64', 'hex') are a different parameter, which is the common confusion here.

Source

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

  getPublicKey(encoding?: any): Buffer | string {
    return this.#diffiehellman.getPublicKey(encoding);
  }
}

DiffieHellmanGroup.prototype = DiffieHellmanGroupImpl.prototype;
DiffieHellmanGroup.prototype.constructor = DiffieHellmanGroup;

function ECDH(curve: string) {
  return new ECDHImpl(curve);
}

function validateEcdhFormat(format: any): void {
  if (
    format !== "compressed" &&
    format !== "uncompressed" &&
    format !== "hybrid"
  ) {
    throw new ERR_CRYPTO_ECDH_INVALID_FORMAT(String(format));
  }
}

function ecdhEncode(
  buffer: Buffer,
  encoding?: any,
): 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

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Remember the order: getPublicKey(encoding, format) — encoding first, format second
  2. Use only 'compressed' | 'uncompressed' | 'hybrid' for the format parameter
  3. If you just want text output, pass the encoding and omit the format: getPublicKey('base64')

Example fix

// before
ecdh.getPublicKey('base64', 'hex'); // 'hex' lands in format -> ERR_CRYPTO_ECDH_INVALID_FORMAT

// after
ecdh.getPublicKey('base64'); // encoding only, uncompressed point
// or explicit point format:
ecdh.getPublicKey(null, 'compressed').toString('base64');
Defensive patterns

Strategy: validation

Validate before calling

const ECDH_FORMATS = new Set(['compressed', 'uncompressed', 'hybrid']);
function assertPointFormat(fmt) {
  if (fmt !== undefined && !ECDH_FORMATS.has(fmt)) throw new TypeError(`invalid ECDH format: ${fmt}`);
}

Type guard

const isEcdhPointFormat = (f) => f === undefined || f === 'compressed' || f === 'uncompressed' || f === 'hybrid';

Try / catch

try { key = ecdh.getPublicKey(null, fmt); } catch (e) { if (e?.code === 'ERR_CRYPTO_ECDH_INVALID_FORMAT') { key = ecdh.getPublicKey(null, 'uncompressed'); } else throw e; }

Prevention

When it happens

Trigger: ecdh.getPublicKey(null, 'base64') — an output encoding passed in the format slot; convertKey(key, curve, inEnc, outEnc, 'hex'); capitalized variants like 'Compressed'; format names invented from WebCrypto ('raw', 'spki').

Common situations: Argument-order mix-ups because getPublicKey(encoding, format) takes the encoding first; passing every string option into the format position; copy-paste from APIs with different parameter orders.

Related errors


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