{"record":{"id":"8ae722c6eb5cded8","repo":"mozilla/pdf.js","slug":"soi-not-found","errorCode":null,"errorMessage":"SOI not found","messagePattern":"SOI not found","errorType":"exception","errorClass":"JpegError","httpStatus":null,"severity":"error","filePath":"src/core/jpg.js","lineNumber":820,"sourceCode":"  }\n  return endOffset;\n}\n\nclass JpegImage {\n  constructor({ decodeTransform = null, colorTransform = -1 } = {}) {\n    this._decodeTransform = decodeTransform;\n    this._colorTransform = colorTransform;\n  }\n\n  static canUseImageDecoder(data, colorTransform = -1) {\n    const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n    let exifOffsets = null;\n    let offset = 0;\n    let numComponents = null;\n    let fileMarker = view.getUint16(offset);\n    offset += 2;\n    if (fileMarker !== /* SOI (Start of Image) = */ 0xffd8) {\n      throw new JpegError(\"SOI not found\");\n    }\n    fileMarker = view.getUint16(offset);\n    offset += 2;\n\n    markerLoop: while (fileMarker !== /* EOI (End of Image) = */ 0xffd9) {\n      switch (fileMarker) {\n        case 0xffe1: // APP1 - Exif\n          // TODO: Remove this once https://github.com/w3c/webcodecs/issues/870\n          //       is fixed.\n          const { appData, oldOffset, newOffset } = readDataBlock(\n            data,\n            view,\n            offset\n          );\n          offset = newOffset;\n\n          // 'Exif\\x00\\x00'\n          if (","sourceCodeStart":802,"sourceCodeEnd":838,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/jpg.js#L802-L838","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Verify the stream bytes actually start with 0xFFD8 before calling canUseImageDecoder.","Check the PDF object's /Filter — if it isn't DCTDecode, route to the correct decoder (JPXDecode, FlateDecode, etc.).","Ensure stream extraction preserves byte 0 (no leading padding/whitespace accidentally included)."],"exampleFix":"// before\nconst canUse = JpegImage.canUseImageDecoder(data);\n\n// after\nconst isJpeg = data.length >= 2 && data[0] === 0xff && data[1] === 0xd8;\nconst canUse = isJpeg ? JpegImage.canUseImageDecoder(data) : null;","handlingStrategy":"validation","validationCode":"function looksLikeJpeg(data) {\n  return data && data.length >= 2 && data[0] === 0xff && data[1] === 0xd8;\n}\n// call before JpegImage.canUseImageDecoder(data)","typeGuard":"function isJpegHeader(data) {\n  return data instanceof Uint8Array && data.length >= 2 && data[0] === 0xff && data[1] === 0xd8;\n}","tryCatchPattern":"try { JpegImage.canUseImageDecoder(data); }\ncatch (e) { if (e.name === 'JpegError') { /* not JPEG, route elsewhere */ } else throw e; }","preventionTips":["Check the first two bytes for 0xFFD8 before invoking the JPEG path.","Verify the PDF object's /Filter is DCTDecode before treating bytes as JPEG.","Ensure stream extraction starts at byte 0 (no offset/whitespace prefix)."],"tags":["jpeg","format-validation","image-decoding"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}