{"record":{"id":"1ebd0331dc2960e4","repo":"denoland/deno","slug":"output-length-outputlength-is-invalid-for-alg","errorCode":null,"errorMessage":"Output length ${outputLength} is invalid for ${algoLower}, which does not support XOF","messagePattern":"Output length (.+?) is invalid for (.+?), which does not support XOF","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/crypto.ts","lineNumber":187,"sourceCode":"      // normalizeEncoding() doesn't handle 'buffer'.\n      if (StringPrototypeToLowerCase(outputEncoding) === \"buffer\") {\n        normalized = \"buffer\";\n      } else {\n        throw new ERR_INVALID_ARG_VALUE(\"outputEncoding\", outputEncoding);\n      }\n    }\n  }\n\n  const algoLower = StringPrototypeToLowerCase(algorithm);\n  const isXof = algoLower === \"shake128\" || algoLower === \"shake256\";\n\n  if (outputLength != null && !isXof) {\n    // For non-XOF hashes, outputLength must match the algorithm's digest size.\n    const testHash = createHash(algorithm);\n    testHash.update(\"\");\n    const expectedLen = testHash.digest().length;\n    if (outputLength !== expectedLen) {\n      throw new Error(\n        `Output length ${outputLength} is invalid for ${algoLower}, which does not support XOF`,\n      );\n    }\n  }\n\n  const h = createHash(\n    algorithm,\n    outputLength != null ? { outputLength } : undefined,\n  );\n  h.update(data);\n\n  if (outputLength === 0) {\n    return normalized === \"buffer\" ? globalThis.Buffer.alloc(0) : \"\";\n  }\n\n  return h.digest(outputEncoding);\n}\n","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/node/polyfills/crypto.ts#L169-L205","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Omit outputLength for fixed-length algorithms like sha256/sha512","Switch to a XOF: crypto.hash('shake128', data, { outputLength: 16 })","To shorten a standard digest, slice the returned Buffer instead of setting outputLength"],"exampleFix":"// before\ncrypto.hash(\"sha256\", data, { outputLength: 16 });\n// after\ncrypto.hash(\"shake128\", data, { outputLength: 16 });\n// or truncate a fixed digest:\n// crypto.hash(\"sha256\", data, \"buffer\").subarray(0, 16)","handlingStrategy":"validation","validationCode":"const XOF = new Set([\"shake128\", \"shake256\"]);\nfunction normalizeHashOptions(algorithm, opts = {}) {\n  if (opts.outputLength != null && !XOF.has(algorithm.toLowerCase())) {\n    delete opts.outputLength; // fixed-length algorithms ignore it\n  }\n  return opts;\n}","typeGuard":"const supportsOutputLength = (algo) => typeof algo === \"string\" && /^shake(128|256)$/i.test(algo);","tryCatchPattern":"try { return crypto.hash(algo, data, opts); }\ncatch (e) {\n  if (/does not support XOF/.test(e.message)) {\n    return crypto.hash(algo, data, \"buffer\").subarray(0, opts.outputLength); // truncate instead\n  } else throw e;\n}","preventionTips":["Treat outputLength as a shake-family-only feature","Truncate standard digests with Buffer#subarray, not outputLength","Compare algorithm names case-insensitively when branching on XOF support"],"tags":["crypto","hash","xof","shake","output-length"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}