denoland/deno · error · DOMException
Unsupported key usage for a PBKDF2 key
Error message
Unsupported key usage for a PBKDF2 key
What it means
Thrown by SecretKeyObject.toCryptoKey() when the algorithm is 'PBKDF2' and the usages array is non-empty and contains any entry other than 'deriveKey' or 'deriveBits'. WebCrypto restricts PBKDF2 keys to key-derivation inputs only, so entries like 'encrypt' or 'sign' are rejected with a SyntaxError DOMException. Note the guard only fires for non-empty arrays — an empty usages array is accepted for PBKDF2 in this polyfill.
Source
Thrown at ext/node/polyfills/internal/crypto/keys.ts:772
);
}
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),
)
) {
throw new DOMException(
"Unsupported key usage for a PBKDF2 key",
"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),
)View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Use only 'deriveKey' and/or 'deriveBits' in the usages array
- Pass an empty usages array [] — the PBKDF2 branch accepts it
- Do encryption/signing with the key you derive via crypto.subtle.deriveBits/deriveKey, never with the PBKDF2 key itself
Example fix
// before
const key = createSecretKey(pw).toCryptoKey('PBKDF2', false, ['sign', 'verify']); // throws
// after
const key = createSecretKey(pw).toCryptoKey('PBKDF2', false, ['deriveBits']);
const aesKey = await crypto.subtle.deriveKey({ name: 'PBKDF2' }, key, { name: 'AES-GCM', length: 256 }, false, ['encrypt']); Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED = ['deriveKey', 'deriveBits'];
const usages = requestedUsages.filter((u) => ALLOWED.includes(u));
const key = secretKeyObject.toCryptoKey('PBKDF2', false, usages); Type guard
const isDerivationUsage = (u: string): boolean => u === 'deriveKey' || u === 'deriveBits';
Try / catch
try {
key = secretKeyObject.toCryptoKey('PBKDF2', false, usages);
} catch (e) {
if (e instanceof DOMException && e.name === 'SyntaxError' && /Unsupported key usage/.test(e.message)) {
key = secretKeyObject.toCryptoKey('PBKDF2', false, ['deriveBits']);
} else throw e;
} Prevention
- Never reuse sign/verify or encrypt/decrypt usage arrays for derivation keys
- Filter usage arrays per algorithm family before import
- Derive first, then apply the derived key to the real operation
When it happens
Trigger: createSecretKey(pw).toCryptoKey('PBKDF2', false, ['encrypt', 'deriveBits']) — any usage outside ['deriveKey','deriveBits'] while at least one usage is present.
Common situations: Reusing an HMAC usages array (['sign','verify']) for a PBKDF2 import; generic wrappers that pass the union of all possible usages; migrating code between subtle.importKey and KeyObject conversion where the same rule applies.
Related errors
- PBKDF2 keys are not extractable
- Unsupported key usage for an HKDF key
- Usages cannot be empty when importing a secret key.
- Usages cannot be empty when importing a private key.
- Zero-length key is not supported
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/0b017d5d13125da8.
Report an issue: GitHub.