gchq/CyberChef · error · Error
Unable to parse JPEG successfully
Error message
Unable to parse JPEG successfully
What it means
Thrown by extractJPEG after the marker-walking loop exits because the stream was exhausted without ever encountering the End-of-Image marker (0xFFD9, case 0xd9 which returns stream.carve()). It indicates a truncated or malformed JPEG that has no EOI. Like the other extractor throws this is a plain Error, not an OperationError.
Source
Thrown at src/core/lib/FileSignatures.mjs:2722
case 0x00: // Byte stuffing
case 0xd0: // Restart
case 0xd1: // Restart
case 0xd2: // Restart
case 0xd3: // Restart
case 0xd4: // Restart
case 0xd5: // Restart
case 0xd6: // Restart
case 0xd7: // Restart
stream.continueUntil(0xff);
break;
default:
stream.continueUntil(0xff);
break;
}
}
throw new Error("Unable to parse JPEG successfully");
}
/**
* GIF extractor.
*
* @param {Uint8Array} bytes
* @param {Number} offset
* @returns {Uint8Array}
*/
export function extractGIF(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Move to application extension block.
stream.continueUntil([0x21, 0xff]);
// Move to Graphic Control Extension for frame #1.
stream.continueUntil([0x21, 0xf9]);View on GitHub (pinned to 4290ea7539)
Solutions
- Ensure the byte stream contains both SOI (0xFFD8) and a trailing EOI (0xFFD9).
- Re-download or re-export the source image to obtain a complete JPEG.
- Check the caller-supplied offset is not past the real EOI.
Defensive patterns
Strategy: validation
Validate before calling
function hasJPEGEOI(bytes, offset = 0) {
for (let i = bytes.length - 2; i >= offset; i--) {
if (bytes[i] === 0xff && bytes[i + 1] === 0xd9) return true;
}
return false;
}
if (!looksLikeJPEG(bytes, offset) || !hasJPEGEOI(bytes, offset)) {
throw new Error("JPEG is truncated (missing EOI marker)");
}
extractJPEG(bytes, offset); Type guard
const hasCompleteJPEGFraming = (bytes, offset = 0) => bytes[offset] === 0xff && bytes[offset + 1] === 0xd8 && bytes[bytes.length - 2] === 0xff && bytes[bytes.length - 1] === 0xd9;
Try / catch
try {
extractJPEG(bytes, offset);
} catch (err) {
if (/Unable to parse JPEG successfully/.test(err.message)) {
// truncated/missing EOI; re-acquire the file
} else throw err;
} Prevention
- Ensure the byte stream includes both SOI (FFD8) and a trailing EOI (FFD9).
- Re-download or re-export images that may have been truncated in transfer.
- Validate framing markers before invoking the extractor.
When it happens
Trigger: Feeding extractJPEG a JPEG whose EOI marker is missing (cut-off download, appended garbage, or a file terminated by a different marker); an offset that starts past the EOI; crafted data that loops until bytes run out.
Common situations: Incomplete file transfer; image intentionally missing EOI (some cameras/embedded tools); progressive JPEG whose scan data was truncated; data with embedded thumbnails where the outer stream ends early.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid marker while parsing JPEG at pos ${stream.position}:
- Not a valid RTF file
- Invalid block type while parsing DEFLATE stream at pos ${str
- Invalid Huffman Code length while parsing DEFLATE block at p
- Invalid recipe
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/2ddf74a2b891988e.
Report an issue: GitHub.