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
- Use a supported dashed name: aes-128/192/256-cbc|ctr|gcm, chacha20, chacha20-poly1305, des-ede3-cbc, or the aes-*-wrap variants.
- Fail fast at startup by test-creating the cipher (or listing crypto.getCiphers()) instead of failing at first encrypt.
- 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
- Store algorithm names in typed constants, never assemble them from string fragments.
- Validate config-loaded algorithm names at process startup, not at first encrypt.
- When porting Node/OpenSSL code, cross-check each algorithm against the supported list.
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
- ERR_INVALID_ARG_TYPE
- ERR_CRYPTO_INVALID_STATE
- Trying to add data in unsupported state
- ERR_UNKNOWN_ENCODING
- ERR_INVALID_ARG_VALUE
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/d44d5e5b0612f8c0.
Report an issue: GitHub.