mozilla/pdf.js · warning · DNLMarkerError

Found EOI marker (0xFFD9) while parsing scan data, possibly

Error message

Found EOI marker (0xFFD9) while parsing scan data, possibly caused by incorrect `scanLines` parameter

What it means

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.

Source

Thrown at src/core/jpg.js:175

            throw new DNLMarkerError(
              "Found DNL marker (0xFFDC) while parsing scan data",
              scanLines
            );
          }
        } else if (nextByte === /* EOI = */ 0xd9) {
          if (parseDNLMarker) {
            // NOTE: only 8-bit JPEG images are supported in this decoder.
            const maybeScanLines = blockRow * (frame.precision === 8 ? 8 : 0);
            // Heuristic to attempt to handle corrupt JPEG images with too
            // large `scanLines` parameter, by falling back to the currently
            // parsed number of scanLines when it's at least (approximately)
            // one "half" order of magnitude smaller than expected (fixes
            // issue10880.pdf, issue10989.pdf, issue15492.pdf).
            if (
              maybeScanLines > 0 &&
              Math.round(frame.scanLines / maybeScanLines) >= 5
            ) {
              throw new DNLMarkerError(
                "Found EOI marker (0xFFD9) while parsing scan data, " +
                  "possibly caused by incorrect `scanLines` parameter",
                maybeScanLines
              );
            }
          }
          throw new EOIMarkerError(
            "Found EOI marker (0xFFD9) while parsing scan data"
          );
        }
        throw new JpegError(
          `unexpected marker ${((bitsData << 8) | nextByte).toString(16)}`
        );
      }
      // unstuff 0
    }
    bitsCount = 7;
    return bitsData >>> 7;

View on GitHub (pinned to 5903d58d58)

Solutions

  1. 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.
  2. Re-encode the offending JPEG so its SOF height equals the true pixel height.
  3. Rebuild the PDF with corrected image dimensions to avoid the mismatch.
  4. If invoking the decoder directly with parseDNLMarker=false, the EOI will instead raise EOIMarkerError (see error 158).
Defensive patterns

Strategy: try-catch

Validate before calling

// Heuristic mirroring pdf.js: flag JPEGs whose declared height is implausible.
function jpegHeightLikelyOversized(declaredScanLines, plausibleScanLines) {
  return plausibleScanLines > 0 &&
    Math.round(declaredScanLines / plausibleScanLines) >= 5;
}

Type guard

function isRecoverableEoiDnlError(err) {
  return err?.name === 'DNLMarkerError' && typeof err.scanLines === 'number' &&
    err.scanLines > 0;
}

Try / catch

// Let pdf.js recover; if wrapping the decoder directly:
try { decodeScan(...); }
catch (err) {
  if (err?.name === 'DNLMarkerError') {
    frame.scanLines = err.scanLines;
  } else if (err?.name === 'EOIMarkerError') {
    throw err; // unrecoverable
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13). Data as JSON: /api/errors/90c44af6b32d9178. Report an issue: GitHub.