denoland/deno · error · ERR_CRYPTO_UNKNOWN_CIPHER

ERR_CRYPTO_UNKNOWN_CIPHER

ERR_CRYPTO_UNKNOWN_CIPHER

Error message

Unknown cipher

What it means

After confirming cipher is a string, the polyfill checks it against crypto.getCiphers() (ext/node/polyfills/internal/crypto/keygen.ts:334-337) and throws ERR_CRYPTO_UNKNOWN_CIPHER when the name is not in the list. The check is an exact, case-sensitive includes(), so uppercase spellings and aliases not exposed by the OpenSSL build fail just like invented names. Deno's supported set can also differ from a full Node/OpenSSL build.

Source

Thrown at ext/node/polyfills/internal/crypto/keygen.ts:335

}

function parsePrivateKeyEncoding(
  enc: any,
  keyType: string | undefined,
  objName: string,
) {
  validateObject(enc, "options");

  const { format, type } = parseKeyFormatAndType(enc, keyType, false, objName);

  const { cipher, passphrase } = enc;

  if (cipher != null) {
    if (typeof cipher !== "string") {
      throw new ERR_INVALID_ARG_VALUE(option("cipher", objName), cipher);
    }
    if (!getCiphers().includes(cipher)) {
      throw new ERR_CRYPTO_UNKNOWN_CIPHER();
    }
    if (
      format === "der" &&
      (type === "pkcs1" || type === "sec1")
    ) {
      throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(
        type,
        "does not support encryption",
      );
    }
  } else if (passphrase !== undefined) {
    throw new ERR_INVALID_ARG_VALUE(option("cipher", objName), cipher);
  }

  if (cipher != null && !isStringOrBuffer(passphrase)) {
    throw new ERR_INVALID_ARG_VALUE(option("passphrase", objName), passphrase);
  }

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pick the name from crypto.getCiphers() at runtime - e.g. verify getCiphers().includes(cipher) before generating.
  2. Use canonical lowercase OpenSSL names such as 'aes-256-cbc' or 'aes-128-gcm'.
  3. Make the cipher configurable with a safe default so a missing name falls back rather than crashing.

Example fix

// before
privateKeyEncoding: { cipher: 'AES-256-CBC', passphrase: 'pw', /* ... */ } // not in getCiphers()

// after
const cipher = 'aes-256-cbc';
if (!crypto.getCiphers().includes(cipher)) throw new Error(`cipher unavailable: ${cipher}`);
privateKeyEncoding: { cipher, passphrase: 'pw', /* ... */ }
Defensive patterns

Strategy: validation

Validate before calling

const cipher = String(cfg.cipher || 'aes-256-cbc');
if (!crypto.getCiphers().includes(cipher)) {
  throw new Error(`cipher '${cipher}' unavailable in this runtime; pick from crypto.getCiphers()`);
}
privateKeyEncoding: { format: 'pem', type: 'pkcs8', cipher, passphrase };

Type guard

function isAvailableCipher(name) {
  return typeof name === 'string' && crypto.getCiphers().includes(name);
}

Try / catch

try { crypto.generateKeyPairSync(alg, opts); }
catch (e) {
  if (e.code === 'ERR_CRYPTO_UNKNOWN_CIPHER') {
    opts.privateKeyEncoding.cipher = 'aes-256-cbc';
    return crypto.generateKeyPairSync(alg, opts);
  }
  throw e;
}

Prevention

When it happens

Trigger: cipher: 'AES-256-CBC' (uppercase, case-sensitive miss); typo like 'aes-256-cbx'; a cipher not compiled into the runtime (e.g. 'des3' variants, 'camellia-256-cbc' depending on build); a cipher name from a different crypto stack (WebCrypto AES-GCM label used verbatim).

Common situations: Cipher names from config files, IaC templates, or documentation that use different casing; hardcoding a legacy cipher the platform dropped; running the same code on Node and Deno where the available cipher lists differ.

Related errors


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