{"record":{"id":"b95b37831906c68f","repo":"mozilla/pdf.js","slug":"invalid-huffman-sequence","errorCode":null,"errorMessage":"invalid huffman sequence","messagePattern":"invalid huffman sequence","errorType":"exception","errorClass":"JpegError","httpStatus":null,"severity":"error","filePath":"src/core/jpg.js","lineNumber":206,"sourceCode":"        );\n      }\n      // unstuff 0\n    }\n    bitsCount = 7;\n    return bitsData >>> 7;\n  }\n\n  function decodeHuffman(tree) {\n    let node = tree;\n    while (true) {\n      node = node[readBit()];\n      switch (typeof node) {\n        case \"number\":\n          return node;\n        case \"object\":\n          continue;\n      }\n      throw new JpegError(\"invalid huffman sequence\");\n    }\n  }\n\n  function receive(length) {\n    let n = 0;\n    while (length > 0) {\n      n = (n << 1) | readBit();\n      length--;\n    }\n    return n;\n  }\n\n  function receiveAndExtend(length) {\n    if (length === 1) {\n      return readBit() === 1 ? 1 : -1;\n    }\n    const n = receive(length);\n    if (n >= 1 << (length - 1)) {","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/jpg.js#L188-L224","documentation":"Thrown by decodeHuffman() while walking a JPEG Huffman tree bit-by-bit. The loop expects each visited node to be either a number (leaf -> decoded symbol) or an object (branch -> keep traversing). When node becomes undefined (no child for the read bit), typeof falls through the switch and the error fires. This means the entropy-coded bit stream does not match any valid Huffman code path in the loaded table.","triggerScenarios":"Reached during baseline/progressive JPEG scan decoding (decodeBaseline, decodeDCFirst, decodeACSuccessive, etc.) when a Huffman table (huffmanTableDC/huffmanTableAC) is malformed or the scan bit-stream is corrupted/truncated so the tree walk hits a missing branch. Also fires if the wrong table index was assigned to a component.","commonSituations":"Truncated JPEG data embedded in a PDF (partial stream), a corrupted DHT marker that built an incomplete tree, or an encoder that emitted bits inconsistent with the declared table. Common with PDFs produced by broken scanner/fax pipelines or with mismatched DHT/SOS component selectors.","solutions":["Re-extract the raw JPEG stream from the PDF and validate it with an external JPEG decoder (e.g. libjpeg, ImageMagick identify) to confirm corruption.","If the stream is truncated, ensure the PDF object's /Length or stream boundaries are correct and that range-request fetching delivered all bytes.","Verify the DHT (0xFFC4) markers define complete Huffman tables before the SOS (0xFFDA) scan references them.","If the image is non-critical, catch JpegError and render a placeholder instead of failing the whole page render."],"exampleFix":"// before\nconst jpegImg = new JpegImage();\njpegImg.parse(data);\nconst pixels = jpegImg.getData({ width, height });\n\n// after — guard decode so one bad image doesn't kill page rendering\ntry {\n  const jpegImg = new JpegImage();\n  jpegImg.parse(data);\n  pixels = jpegImg.getData({ width, height });\n} catch (e) {\n  if (e.name === 'JpegError') {\n  pixels = null;\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  jpegImg.parse(data);\n  pixels = jpegImg.getData({ width, height });\n} catch (e) {\n  if (e.name === 'JpegError') { pixels = null; }\n  throw e;\n}","preventionTips":["Validate embedded JPEG streams with an external decoder before relying on PDF.js for untrusted PDFs.","Ensure PDF stream extraction preserves exact byte boundaries (correct /Length, full range fetch).","Isolate image decoding from page rendering so one corrupt image doesn't abort the whole render."],"tags":["jpeg","image-decoding","huffman","corrupt-data"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}