denoland/deno · error · DOMException
Unsupported key usage for an HKDF key
Error message
Unsupported key usage for an HKDF key
What it means
Thrown by SecretKeyObject.toCryptoKey() when the algorithm is 'HKDF' and the usages array is non-empty and contains anything other than 'deriveKey' or 'deriveBits'. HKDF keys exist solely as derivation inputs in WebCrypto, so any other usage entry is rejected with a SyntaxError DOMException. As with PBKDF2, an empty usages array is accepted by this branch.
Source
Thrown at ext/node/polyfills/internal/crypto/keys.ts:792
"SyntaxError",
);
}
} else if (algName === "HKDF") {
if (extractable) {
throw new DOMException(
"HKDF keys are not extractable",
"SyntaxError",
);
}
if (
usages.length > 0 &&
ArrayPrototypeSome(
usages,
(u: string) =>
!ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u),
)
) {
throw new DOMException(
"Unsupported key usage for an HKDF key",
"SyntaxError",
);
}
} else if (algName === "HMAC") {
if (usages.length === 0) {
throw new DOMException(
"Usages cannot be empty when importing a secret key.",
"SyntaxError",
);
}
const alg = algorithm as { length?: number };
if (alg.length !== undefined && alg.length === 0) {
throw new DOMException(
"HmacImportParams.length cannot be 0",
"DataError",
);
}View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Use only 'deriveKey' and/or 'deriveBits' for HKDF
- Pass [] if you have no specific usage to declare
- Derive with crypto.subtle.deriveBits/deriveKey and use the output key for the actual operation
Example fix
// before
const hkdfKey = createSecretKey(ikm).toCryptoKey('HKDF', false, ['sign']); // throws
// after
const hkdfKey = createSecretKey(ikm).toCryptoKey('HKDF', false, ['deriveBits']);
const okm = await crypto.subtle.deriveBits({ name: 'HKDF', hash: 'SHA-256', salt, info }, hkdfKey, 256); Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED = ['deriveKey', 'deriveBits'];
const usages = requestedUsages.filter((u) => ALLOWED.includes(u));
const key = secretKeyObject.toCryptoKey('HKDF', false, usages); Type guard
const isDerivationUsage = (u: string): boolean => u === 'deriveKey' || u === 'deriveBits';
Try / catch
try {
key = secretKeyObject.toCryptoKey('HKDF', false, usages);
} catch (e) {
if (e instanceof DOMException && e.name === 'SyntaxError' && /Unsupported key usage/.test(e.message)) {
key = secretKeyObject.toCryptoKey('HKDF', false, ['deriveBits']);
} else throw e;
} Prevention
- Scope usage arrays to the algorithm being imported
- Do not share one usages constant across HMAC, AES and HKDF code paths
- Review WebCrypto usage tables per algorithm when adding a new algorithm
When it happens
Trigger: createSecretKey(ikm).toCryptoKey('HKDF', false, ['deriveBits', 'encrypt']) — at least one usage outside ['deriveKey','deriveBits'].
Common situations: One generic usages array shared across HMAC, AES and HKDF imports; wrappers that copy the caller's requested operations straight through; upgrading key-derivation code from scrypt/pbkdf2 to HKDF while keeping old usages.
Related errors
- Unsupported key usage for a PBKDF2 key
- HKDF keys are not extractable
- Usages cannot be empty when importing a secret key.
- Usages cannot be empty when importing a private key.
- ERR_OUT_OF_RANGE
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/b4795407520f81a2.
Report an issue: GitHub.