denoland/deno · error · Error

Output length ${outputLength} is invalid for ${algoLower}, w

Error message

Output length ${outputLength} is invalid for ${algoLower}, which does not support XOF

What it means

When crypto.hash receives outputLength, only XOF algorithms (shake128, shake256) accept arbitrary lengths. For fixed-length algorithms the polyfill computes the expected digest size by hashing an empty string and requires outputLength to equal it exactly; otherwise it throws a plain Error (no code property) whose message ends with 'which does not support XOF'.

Source

Thrown at ext/node/polyfills/crypto.ts:187

      // normalizeEncoding() doesn't handle 'buffer'.
      if (StringPrototypeToLowerCase(outputEncoding) === "buffer") {
        normalized = "buffer";
      } else {
        throw new ERR_INVALID_ARG_VALUE("outputEncoding", outputEncoding);
      }
    }
  }

  const algoLower = StringPrototypeToLowerCase(algorithm);
  const isXof = algoLower === "shake128" || algoLower === "shake256";

  if (outputLength != null && !isXof) {
    // For non-XOF hashes, outputLength must match the algorithm's digest size.
    const testHash = createHash(algorithm);
    testHash.update("");
    const expectedLen = testHash.digest().length;
    if (outputLength !== expectedLen) {
      throw new Error(
        `Output length ${outputLength} is invalid for ${algoLower}, which does not support XOF`,
      );
    }
  }

  const h = createHash(
    algorithm,
    outputLength != null ? { outputLength } : undefined,
  );
  h.update(data);

  if (outputLength === 0) {
    return normalized === "buffer" ? globalThis.Buffer.alloc(0) : "";
  }

  return h.digest(outputEncoding);
}

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Omit outputLength for fixed-length algorithms like sha256/sha512
  2. Switch to a XOF: crypto.hash('shake128', data, { outputLength: 16 })
  3. To shorten a standard digest, slice the returned Buffer instead of setting outputLength

Example fix

// before
crypto.hash("sha256", data, { outputLength: 16 });
// after
crypto.hash("shake128", data, { outputLength: 16 });
// or truncate a fixed digest:
// crypto.hash("sha256", data, "buffer").subarray(0, 16)
Defensive patterns

Strategy: validation

Validate before calling

const XOF = new Set(["shake128", "shake256"]);
function normalizeHashOptions(algorithm, opts = {}) {
  if (opts.outputLength != null && !XOF.has(algorithm.toLowerCase())) {
    delete opts.outputLength; // fixed-length algorithms ignore it
  }
  return opts;
}

Type guard

const supportsOutputLength = (algo) => typeof algo === "string" && /^shake(128|256)$/i.test(algo);

Try / catch

try { return crypto.hash(algo, data, opts); }
catch (e) {
  if (/does not support XOF/.test(e.message)) {
    return crypto.hash(algo, data, "buffer").subarray(0, opts.outputLength); // truncate instead
  } else throw e;
}

Prevention

When it happens

Trigger: crypto.hash('sha256', 'x', { outputLength: 16 }) — sha256 always yields 32 bytes, so this throws; { outputLength: 32 } would pass; outputLength: 0 skips the length check entirely and returns empty output. outputLength != null (not undefined/null) is what arms the check.

Common situations: Reusing an options bag written for shake128/shake256 with sha2/sha3 algorithms; assuming outputLength truncates the digest (it does not — only XOFs can vary output); sharing hashing helpers across algorithm families.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/1ebd0331dc2960e4. Report an issue: GitHub.