denoland/deno · error · DOMException

Usages cannot be empty when importing a secret key.

Error message

Usages cannot be empty when importing a secret key.

What it means

Thrown by SecretKeyObject.toCryptoKey() when converting a secret KeyObject to a CryptoKey with algorithm 'HMAC' and an empty usages array. WebCrypto import rules require at least one usage, because a key that can perform no operation indicates a caller bug. The polyfill surfaces this as a DOMException of type SyntaxError before attempting the import.

Source

Thrown at ext/node/polyfills/internal/crypto/keys.ts:799

          "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",
        );
      }
    } else if (algName === "KMAC128" || algName === "KMAC256") {
      if (usages.length === 0) {
        throw new DOMException(
          "Usages cannot be empty when importing a secret key.",
          "SyntaxError",
        );
      }

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pass at least one valid usage — typically ['sign'] or ['sign','verify'] for HMAC
  2. Audit wrapper defaults so usages can never be an empty array
  3. Derive the usages list from the operation the key will actually perform

Example fix

// before
const key = createSecretKey(secret).toCryptoKey({ name: 'HMAC', hash: 'SHA-256' }, false, []); // throws

// after
const key = createSecretKey(secret).toCryptoKey({ name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
Defensive patterns

Strategy: validation

Validate before calling

if (usages.length === 0) {
  throw new Error(`HMAC key requires usages; got none (caller: ${callerId})`);
}
const key = secretKeyObject.toCryptoKey({ name: 'HMAC', hash }, false, usages);

Try / catch

try {
  key = secretKeyObject.toCryptoKey({ name: 'HMAC', hash }, false, usages);
} catch (e) {
  if (e instanceof DOMException && e.name === 'SyntaxError' && e.message.includes('Usages cannot be empty')) {
    key = secretKeyObject.toCryptoKey({ name: 'HMAC', hash }, false, ['sign']);
  } else throw e;
}

Prevention

When it happens

Trigger: createSecretKey(secret).toCryptoKey({ name: 'HMAC', hash: 'SHA-256' }, false, []) — third argument is an empty array.

Common situations: Generic import wrappers whose usages parameter defaults to []; refactors that drop the usages argument; code that builds usages conditionally and ends up with zero entries for some key types.

Related errors


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