denoland/deno · error · DOMException

HmacImportParams.length cannot be 0

Error message

HmacImportParams.length cannot be 0

What it means

Thrown by SecretKeyObject.toCryptoKey() when the algorithm object for 'HMAC' carries length === 0. HmacImportParams.length is the HMAC key length in bits; zero is not a usable key length. The check only fires when the property is explicitly present (undefined is allowed and uses the default derived from the hash), so this almost always means code passed a computed value that evaluated to 0.

Source

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

          (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",
        );
      }
      const alg = algorithm as { length?: number };
      if (alg.length !== undefined && alg.length === 0) {
        throw new DOMException(
          "KmacImportParams.length cannot be 0",
          "DataError",
        );
      }

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Omit length entirely to use the hash's default key length
  2. Pass the intended length in bits, e.g. 256
  3. Only include length when it is a positive number: build params conditionally

Example fix

// before
const params = { name: 'HMAC', hash: 'SHA-256', length: bits };

// after
const params = { name: 'HMAC', hash: 'SHA-256' };
if (bits > 0) params.length = bits;
Defensive patterns

Strategy: validation

Validate before calling

const params: HmacImportParams = { name: 'HMAC', hash };
if (Number.isFinite(length) && length! > 0) params.length = length;
const key = secretKeyObject.toCryptoKey(params, false, usages);

Type guard

const isValidHmacLength = (n: unknown): n is number =>
  typeof n === 'number' && Number.isInteger(n) && n > 0;

Try / catch

try {
  key = secretKeyObject.toCryptoKey(params, false, usages);
} catch (e) {
  if (e instanceof DOMException && e.name === 'DataError' && /length cannot be 0/.test(e.message)) {
    const { length: _drop, ...rest } = params;
    key = secretKeyObject.toCryptoKey(rest, false, usages);
  } else throw e;
}

Prevention

When it happens

Trigger: createSecretKey(secret).toCryptoKey({ name: 'HMAC', hash: 'SHA-256', length: 0 }, false, ['sign']).

Common situations: length computed from an empty buffer's byteLength (or a *8 bit conversion of zero); config schemas that initialize numeric fields to 0; confusion between bytes and bits when filling the field programmatically.

Related errors


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