mozilla/pdf.js · error · JpegError

SOI not found

Error message

SOI not found

What it means

Thrown by the static method JpegImage.canUseImageDecoder() when the first two bytes of the supplied data are not 0xFFD8 (the JPEG Start-Of-Image marker). canUseImageDecoder is a pre-check that decides whether the platform's native image decoder can handle the stream; if the data isn't JPEG at all, it bails immediately.

Source

Thrown at src/core/jpg.js:820

  }
  return endOffset;
}

class JpegImage {
  constructor({ decodeTransform = null, colorTransform = -1 } = {}) {
    this._decodeTransform = decodeTransform;
    this._colorTransform = colorTransform;
  }

  static canUseImageDecoder(data, colorTransform = -1) {
    const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
    let exifOffsets = null;
    let offset = 0;
    let numComponents = null;
    let fileMarker = view.getUint16(offset);
    offset += 2;
    if (fileMarker !== /* SOI (Start of Image) = */ 0xffd8) {
      throw new JpegError("SOI not found");
    }
    fileMarker = view.getUint16(offset);
    offset += 2;

    markerLoop: while (fileMarker !== /* EOI (End of Image) = */ 0xffd9) {
      switch (fileMarker) {
        case 0xffe1: // APP1 - Exif
          // TODO: Remove this once https://github.com/w3c/webcodecs/issues/870
          //       is fixed.
          const { appData, oldOffset, newOffset } = readDataBlock(
            data,
            view,
            offset
          );
          offset = newOffset;

          // 'Exif\x00\x00'
          if (

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Verify the stream bytes actually start with 0xFFD8 before calling canUseImageDecoder.
  2. Check the PDF object's /Filter — if it isn't DCTDecode, route to the correct decoder (JPXDecode, FlateDecode, etc.).
  3. Ensure stream extraction preserves byte 0 (no leading padding/whitespace accidentally included).

Example fix

// before
const canUse = JpegImage.canUseImageDecoder(data);

// after
const isJpeg = data.length >= 2 && data[0] === 0xff && data[1] === 0xd8;
const canUse = isJpeg ? JpegImage.canUseImageDecoder(data) : null;
Defensive patterns

Strategy: validation

Validate before calling

function looksLikeJpeg(data) {
  return data && data.length >= 2 && data[0] === 0xff && data[1] === 0xd8;
}
// call before JpegImage.canUseImageDecoder(data)

Type guard

function isJpegHeader(data) {
  return data instanceof Uint8Array && data.length >= 2 && data[0] === 0xff && data[1] === 0xd8;
}

Try / catch

try { JpegImage.canUseImageDecoder(data); }
catch (e) { if (e.name === 'JpegError') { /* not JPEG, route elsewhere */ } else throw e; }

Prevention

When it happens

Trigger: Calling JpegImage.canUseImageDecoder(data) where data does not begin with 0xFFD8 — e.g. the bytes are PNG, JBIG2, JPX, or random/corrupt content that was incorrectly tagged as JPEG.

Common situations: A PDF image XObject with /Filter /DCTDecode whose stream is actually another format, or a stream that was truncated before the SOI. Also occurs if the wrong byte slice is passed (offset/length miscalculation when extracting the stream).

Related errors


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