mozilla/pdf.js · error · EOIMarkerError

Found EOI marker (0xFFD9) while parsing scan data

Error message

Found EOI marker (0xFFD9) while parsing scan data

What it means

Thrown as EOIMarkerError when an EOI (0xFFD9) marker is reached during scan parsing and pdf.js cannot recover (either parseDNLMarker is false, or the heuristic for over-large height did not apply). It signals premature end of the JPEG scan data.

Source

Thrown at src/core/jpg.js:182

            // 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;
  }

  function decodeHuffman(tree) {
    let node = tree;
    while (true) {
      node = node[readBit()];
      switch (typeof node) {

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Verify the JPEG byte stream is complete and not truncated (check stream length against expected).
  2. Re-embed a complete JPEG in the source PDF.
  3. If you wrap the decoder, catch EOIMarkerError and present whatever partial scan data was produced.
  4. Enable parseDNLMarker (default in the pdf.js image path) so the recoverable variant (error 157) is attempted first.
Defensive patterns

Strategy: try-catch

Validate before calling

// Check JPEG byte length vs expected MCU count before decoding:
function jpegStreamProbablyComplete(bytes, frame) {
  const expectedMcus = frame.mcusPerLine * frame.mcusPerColumn;
  return bytes.length >= expectedMcus; // crude lower bound
}

Type guard

function isEoiMarkerError(err) {
  return err?.name === 'EOIMarkerError';
}

Try / catch

try { await page.render({ canvasContext }).promise; }
catch (err) {
  if (err?.name === 'EOIMarkerError' || /EOI marker/.test(err?.message || '')) {
    console.warn('JPEG scan truncated; rendering partial image.');
  } else throw err;
}

Prevention

When it happens

Trigger: Decoding a JPEG whose scan ends with 0xFFD9 before the expected number of MCUs, with parseDNLMarker=false OR with a height that does not meet the 5x recovery threshold. Reached during DCTDecode image rendering.

Common situations: Truncated JPEG streams (download/interruption), corrupt image data, or PDFs whose SOF height exactly matches reality but the scan data is short. Distinct from DNLMarkerError in that no recovery is attempted.

Related errors


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