denoland/deno · error · Error

ERR_CRYPTO_UNKNOWN_CIPHER

ERR_CRYPTO_UNKNOWN_CIPHER

Error message

Unknown cipher

What it means

createCipheriv() throws ERR_CRYPTO_UNKNOWN_CIPHER when the algorithm string is not recognized by Deno's Rust crypto backend. The native constructor (ext/node_crypto/cipher.rs) returns the error `Unknown cipher <name>`, which the constructor's catch block detects (TypeError whose message starts with 'Unknown cipher') and converts to Node's ERR_CRYPTO_UNKNOWN_CIPHER so code checking the code property behaves as on Node.

Source

Thrown at ext/node/polyfills/internal/crypto/cipher.ts:235

    this._aesWrapKey = toU8(key);
    this._aesWrapIv = toU8(iv);
    this._context = 1; // non-zero sentinel; not used for wrap ops
  } else {
    try {
      this._context = op_node_create_cipheriv(
        cipher,
        toU8(key),
        toU8(iv),
        authTagLength,
      );
    } catch (e) {
      // The op reports an unrecognized algorithm as a TypeError that includes
      // the cipher name; surface Node's ERR_CRYPTO_UNKNOWN_CIPHER instead.
      if (
        ObjectPrototypeIsPrototypeOf(TypeErrorPrototype, e) &&
        StringPrototypeStartsWith(e.message, "Unknown cipher")
      ) {
        throw new ERR_CRYPTO_UNKNOWN_CIPHER();
      }
      throw e;
    }
    if (this._context == 0) {
      throw new ERR_CRYPTO_UNKNOWN_CIPHER();
    }
  }

  this._needsBlockCache = !this._isAesWrap &&
    !(cipher == "aes-128-gcm" || cipher == "aes-256-gcm" ||
      cipher == "aes-128-ctr" || cipher == "aes-192-ctr" ||
      cipher == "aes-256-ctr" || cipher == "chacha20" ||
      cipher == "chacha20-poly1305");
  this._authTag = undefined;
  this._autoPadding = true;
  this._finalized = false;
  this._decoder = undefined;
}

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Use a supported dashed name: aes-128/192/256-cbc|ctr|gcm, chacha20, chacha20-poly1305, des-ede3-cbc, or the aes-*-wrap variants.
  2. Fail fast at startup by test-creating the cipher (or listing crypto.getCiphers()) instead of failing at first encrypt.
  3. Keep the algorithm in a single typed constant instead of assembling it from string parts.

Example fix

// before
const cipher = crypto.createCipheriv('aes128-gcm', key, iv); // ERR_CRYPTO_UNKNOWN_CIPHER

// after
const ALGO = 'aes-128-gcm';
const cipher = crypto.createCipheriv(ALGO, key, iv);
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED_CIPHERS = new Set([
  'aes-128-cbc','aes-192-cbc','aes-256-cbc',
  'aes-128-ctr','aes-192-ctr','aes-256-ctr',
  'aes-128-gcm','aes-192-gcm','aes-256-gcm',
  'chacha20','chacha20-poly1305','des-ede3-cbc',
]);
function assertCipherSupported(algo: string): void {
  if (!SUPPORTED_CIPHERS.has(algo))
    throw new Error(`Unsupported cipher algorithm: '${algo}'`);
}

Try / catch

try { cipher = crypto.createCipheriv(algo, key, iv); } catch (e) { if (e.code === 'ERR_CRYPTO_UNKNOWN_CIPHER') { cipher = crypto.createCipheriv('aes-256-gcm', key, iv); /* or fail config */ } else throw e; }

Prevention

When it happens

Trigger: createCipheriv('aes128-gcm') (OpenSSL legacy name without dashes); typos or whitespace like 'aes-128-gcm '; algorithms Node/OpenSSL supports but this backend does not (e.g. 'camellia-128-cbc', 'aes-128-ocb', 'id-aes128-gcm').

Common situations: Algorithm names sourced from env vars or YAML config with a typo; strings copied from OpenSSL command-line docs; running Node-targeted encryption code under Deno where the supported set (aes-{128,192,256}-{cbc,ctr,gcm}, chacha20, chacha20-poly1305, des-ede3-cbc, aes-*-wrap) is smaller.

Related errors


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