denoland/deno · error · DOMException
Zero-length key is not supported
Error message
Zero-length key is not supported
What it means
SecretKeyObject.toCryptoKey exports the secret key's raw bytes and refuses zero-length material with a DataError DOMException, mirroring the WebCrypto rule that an imported secret must carry at least one byte. This guard runs before algorithm-specific checks (PBKDF2/HKDF/HMAC usage validation) and before importCryptoKeySync.
Source
Thrown at ext/node/polyfills/internal/crypto/keys.ts:751
type: "NodeCryptoKeyObject",
keyType: "secret",
keyData: new Uint8Array(op_node_export_secret_key(this[kHandle])),
};
}
toCryptoKey(
algorithm: string | object,
extractable: boolean,
usages: string[],
): CryptoKey {
const algName = typeof algorithm === "string"
? algorithm
: (algorithm as { name: string }).name;
const rawData = new Uint8Array(op_node_export_secret_key(this[kHandle]));
if (TypedArrayPrototypeGetByteLength(rawData) === 0) {
throw new DOMException(
"Zero-length key is not supported",
"DataError",
);
}
if (algName === "PBKDF2") {
if (extractable) {
throw new DOMException(
"PBKDF2 keys are not extractable",
"SyntaxError",
);
}
if (
usages.length > 0 &&
ArrayPrototypeSome(
usages,
(u: string) =>
!ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Validate byte length > 0 when creating the secret: if (!buf.length) throw ... at startup
- Treat empty secrets as configuration errors and refuse to boot
- Watch for Buffer.slice/subarray mistakes that produce zero-length views
- For AES keys also meet the algorithm minimum (16/24/32 bytes) — later checks enforce that separately
Example fix
// before: empty env value becomes a zero-length key
const secret = crypto.createSecretKey(Buffer.from(process.env.API_SECRET ?? ''));
const ck = secret.toCryptoKey('AES-GCM', false, ['encrypt']); // DataError
// after: fail fast on empty material
const raw = Buffer.from(process.env.API_SECRET ?? '', 'base64');
if (raw.length === 0) throw new Error('API_SECRET is empty');
const ck = crypto.createSecretKey(raw).toCryptoKey('AES-GCM', false, ['encrypt']); Defensive patterns
Strategy: validation
Validate before calling
function toCryptoKey(secretKeyObject, alg, extractable, usages) {
const raw = Buffer.from(secretKeyObject.export());
if (raw.length === 0) {
throw new Error('refusing to convert a zero-length secret key');
}
return secretKeyObject.toCryptoKey(alg, extractable, usages);
} Type guard
function isNonEmptySecret(key: crypto.KeyObject): boolean {
return key.type === 'secret' &&
Buffer.from(key.export()).length > 0;
} Try / catch
try {
return secretKey.toCryptoKey(alg, extractable, usages);
} catch (err) {
if (err instanceof DOMException && err.name === 'DataError' &&
/Zero-length key/.test(err.message)) {
throw new Error('Secret material is empty — check env/config source');
}
throw err;
} Prevention
- Validate secret length > 0 (and >= algorithm minimum) at configuration load time
- Treat empty-but-present env vars as missing
- Test key plumbing with the same shapes production uses (base64 env values, file reads)
When it happens
Trigger: createSecretKey(Buffer.alloc(0)).toCryptoKey(alg, extractable, usages); a secret built from an empty string/env value (Buffer.from('') has length 0) then converted to a CryptoKey via KeyObject.toCryptoKey (used by webcrypto interop).
Common situations: An env var that exists but is empty (API_SECRET='') decoded to an empty buffer; slicing a buffer with wrong offsets yielding length 0; a default empty secret in staging config that nobody exercised; test fixtures with empty key material.
Related errors
- PBKDF2 keys are not extractable
- Unsupported key usage for a PBKDF2 key
- HKDF keys are not extractable
- Unsupported key usage for an HKDF key
- Usages cannot be empty when importing a secret key.
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/c6f4276da57ed63c.
Report an issue: GitHub.