{"record":{"id":"90c44af6b32d9178","repo":"mozilla/pdf.js","slug":"found-eoi-marker-0xffd9-while-parsing-scan-data","errorCode":null,"errorMessage":"Found EOI marker (0xFFD9) while parsing scan data, possibly caused by incorrect `scanLines` parameter","messagePattern":"Found EOI marker \\(0xFFD9\\) while parsing scan data, possibly caused by incorrect `scanLines` parameter","errorType":"exception","errorClass":"DNLMarkerError","httpStatus":null,"severity":"warning","filePath":"src/core/jpg.js","lineNumber":175,"sourceCode":"            throw new DNLMarkerError(\n              \"Found DNL marker (0xFFDC) while parsing scan data\",\n              scanLines\n            );\n          }\n        } else if (nextByte === /* EOI = */ 0xd9) {\n          if (parseDNLMarker) {\n            // NOTE: only 8-bit JPEG images are supported in this decoder.\n            const maybeScanLines = blockRow * (frame.precision === 8 ? 8 : 0);\n            // Heuristic to attempt to handle corrupt JPEG images with too\n            // large `scanLines` parameter, by falling back to the currently\n            // parsed number of scanLines when it's at least (approximately)\n            // one \"half\" order of magnitude smaller than expected (fixes\n            // issue10880.pdf, issue10989.pdf, issue15492.pdf).\n            if (\n              maybeScanLines > 0 &&\n              Math.round(frame.scanLines / maybeScanLines) >= 5\n            ) {\n              throw new DNLMarkerError(\n                \"Found EOI marker (0xFFD9) while parsing scan data, \" +\n                  \"possibly caused by incorrect `scanLines` parameter\",\n                maybeScanLines\n              );\n            }\n          }\n          throw new EOIMarkerError(\n            \"Found EOI marker (0xFFD9) while parsing scan data\"\n          );\n        }\n        throw new JpegError(\n          `unexpected marker ${((bitsData << 8) | nextByte).toString(16)}`\n        );\n      }\n      // unstuff 0\n    }\n    bitsCount = 7;\n    return bitsData >>> 7;","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/jpg.js#L157-L193","documentation":"Thrown as DNLMarkerError when an EOI (0xFFD9) marker ends the scan and a heuristic detects the declared frame.scanLines is far larger (>= 5x) than the lines actually parsed (maybeScanLines). pdf.js uses this to recover by substituting the parsed line count, fixing corrupt JPEGs with an oversized height. Only thrown when parseDNLMarker is true.","triggerScenarios":"Decoding a JPEG whose SOF height is wildly larger than the real image, the scan ends with EOI, and maybeScanLines (blockRow*8 for 8-bit) is at least 5x smaller than frame.scanLines. Triggered by DCTDecode image rendering of such corrupt streams.","commonSituations":"The classic pdf.js regressions issue10880.pdf, issue10989.pdf, issue15492.pdf; any JPEG whose declared height was padded/inflated and never corrected by a DNL marker.","solutions":["Allow pdf.js to recover: DNLMarkerError.scanLines carries the corrected count and is handled internally — do not rethrow it as fatal in a custom decoder wrapper.","Re-encode the offending JPEG so its SOF height equals the true pixel height.","Rebuild the PDF with corrected image dimensions to avoid the mismatch.","If invoking the decoder directly with parseDNLMarker=false, the EOI will instead raise EOIMarkerError (see error 158)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Heuristic mirroring pdf.js: flag JPEGs whose declared height is implausible.\nfunction jpegHeightLikelyOversized(declaredScanLines, plausibleScanLines) {\n  return plausibleScanLines > 0 &&\n    Math.round(declaredScanLines / plausibleScanLines) >= 5;\n}","typeGuard":"function isRecoverableEoiDnlError(err) {\n  return err?.name === 'DNLMarkerError' && typeof err.scanLines === 'number' &&\n    err.scanLines > 0;\n}","tryCatchPattern":"// Let pdf.js recover; if wrapping the decoder directly:\ntry { decodeScan(...); }\ncatch (err) {\n  if (err?.name === 'DNLMarkerError') {\n    frame.scanLines = err.scanLines;\n  } else if (err?.name === 'EOIMarkerError') {\n    throw err; // unrecoverable\n  } else throw err;\n}","preventionTips":["Do not unwrap DNLMarkerError as fatal; use err.scanLines to recover.","Re-encode JPEGs so SOF height matches the real line count.","Keep parseDNLMarker=true (default) to benefit from recovery."],"tags":["pdf","jpeg","dctdecode","eoi-marker","recoverable"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}