denoland/deno · error · Error

Failed to convert Buffer to EC_POINT

Error message

Failed to convert Buffer to EC_POINT

What it means

A generic Error thrown by ECDH.convertKey() when op_node_ecdh_encode_pubkey fails for any reason other than an unsupported curve. It means the key bytes could not be parsed as a public key EC point on the specified curve — the buffer never became an EC_POINT, so it cannot be re-encoded to compressed/uncompressed/hybrid form.

Source

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

        throw new ERR_CRYPTO_ECDH_INVALID_FORMAT(format);
      }
    } else {
      compress = false;
    }

    let result;
    try {
      result = Buffer.from(
        op_node_ecdh_encode_pubkey(curve, buf, compress),
      );
    } catch (e) {
      if (
        ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e) &&
        (e as Error).message === "Unsupported curve"
      ) {
        throw new TypeError("Invalid EC curve name");
      }
      throw new Error("Failed to convert Buffer to EC_POINT");
    }

    if (format === "hybrid") {
      // Hybrid format: same as uncompressed but first byte is 06 or 07
      // Get compressed form to determine parity
      const compressedBuf = Buffer.from(
        op_node_ecdh_encode_pubkey(curve, buf, true),
      );
      // 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;

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Verify the input length: uncompressed points are 1 + 2*fieldSize bytes (P-256: 65, P-384: 97, P-521: 133), compressed are 1 + fieldSize
  2. Check the first byte is 0x04 (uncompressed) or 0x02/0x03 (compressed) and prepend 0x04 if the peer sent bare X||Y coordinates
  3. Confirm inputEncoding matches how the key was produced (a hex string must be read with 'hex')
  4. Make sure you are converting a public key, not a private scalar or a DER/PEM blob — decode those first

Example fix

// before
const point = Buffer.concat([x, y]); // 64 bytes, no prefix
const out = crypto.ECDH.convertKey(point, 'prime256v1');

// after
const point = Buffer.concat([Buffer.from([0x04]), x, y]); // 65 bytes with 0x04 prefix
const out = crypto.ECDH.convertKey(point, 'prime256v1');
Defensive patterns

Strategy: validation

Validate before calling

const FIELD = { prime256v1: 32, secp384r1: 48, secp521r1: 66 }[curve]!;
const ok = buf.length === 1 + 2 * FIELD && buf[0] === 0x04;
if (!ok) throw new RangeError('key is not an uncompressed point for ' + curve);
const out = crypto.ECDH.convertKey(key, curve, inputEncoding, outputEncoding, format);

Type guard

const isUncompressedPoint = (b: Uint8Array, fieldSize: number): boolean =>
  b.length === 1 + 2 * fieldSize && (b[0] === 0x04 || b[0] === 0x06 || b[0] === 0x07);

Try / catch

catch (e) { if (e.message === 'Failed to convert Buffer to EC_POINT') { /* reject peer key, re-request */ } throw e; }

Prevention

When it happens

Trigger: Passing key bytes with the wrong length for the curve (e.g. 64 raw bytes instead of a 65-byte 0x04-prefixed point for P-256), a missing or invalid prefix byte (0x02/0x03/0x04), a point that is not on the curve, or a private key / random data supplied where a public key point is expected.

Common situations: Peer systems send the raw X||Y coordinates without the uncompressed 0x04 header; hex strings decoded with the wrong encoding ('base64' vs 'hex'); passing a Buffer that was sliced with wrong offsets; feeding a secp256k1 key into a prime256v1 conversion.

Related errors


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