mozilla/pdf.js · error · JpegError
invalid ACn encoding
Error message
invalid ACn encoding
What it means
Thrown inside decodeACSuccessive() during progressive JPEG successive-approximation AC refinement. After Huffman-decoding an AC symbol, the category nibble s must be 0 (EOB/run) or 1 (single refinement bit); any value 2-15 is illegal for successive refinement and triggers this error. It enforces a constraint from ITU-T T.81 section G.1.1.2.
Source
Thrown at src/core/jpg.js:317
while (k <= e) {
const offsetZ = blockOffset + dctZigZag[k];
const sign = component.blockData[offsetZ] < 0 ? -1 : 1;
switch (successiveACState) {
case 0: // initial state
rs = decodeHuffman(component.huffmanTableAC);
s = rs & 15;
r = rs >> 4;
if (s === 0) {
if (r < 15) {
eobrun = receive(r) + (1 << r);
successiveACState = 4;
} else {
r = 16;
successiveACState = 1;
}
} else {
if (s !== 1) {
throw new JpegError("invalid ACn encoding");
}
successiveACNextValue = receiveAndExtend(s);
successiveACState = r ? 2 : 3;
}
continue;
case 1: // skipping r zero items
case 2:
if (component.blockData[offsetZ]) {
component.blockData[offsetZ] += sign * (readBit() << successive);
} else {
r--;
if (r === 0) {
successiveACState = successiveACState === 2 ? 3 : 0;
}
}
break;
case 3: // set value for a zero item
if (component.blockData[offsetZ]) {View on GitHub (pinned to 5903d58d58)
Solutions
- Decode the JPEG with a reference decoder (libjpeg-turbo) to confirm the progressive scan data is malformed.
- If you control encoding, ensure successive AC refinement scans only emit category 0/1 symbols.
- If the PDF is untrusted/legacy, wrap the parse+getData call in a try/catch on JpegError and fall back to a placeholder or the native browser decoder.
Example fix
// before
jpegImg.parse(data);
const out = jpegImg.getData({ width: jpegImg.width, height: jpegImg.height });
// after
try {
jpegImg.parse(data);
out = jpegImg.getData({ width: jpegImg.width, height: jpegImg.height });
} catch (e) {
if (e.name === 'JpegError') { out = null; }
throw e;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
jpegImg.parse(data);
out = jpegImg.getData({ width: jpegImg.width, height: jpegImg.height });
} catch (e) {
if (e.name === 'JpegError') { out = null; }
throw e;
} Prevention
- When generating progressive JPEGs, use a mature encoder (libjpeg-turbo/mozjpeg) to guarantee spec-compliant successive-approximation scans.
- Validate progressive JPEGs with a reference decoder before embedding in PDFs.
- Catch JpegError at the image-render boundary and substitute a placeholder.
When it happens
Trigger: Fires only for progressive JPEGs (SOF2, 0xFFC2) during a successive-approximation AC scan, when the decoded AC Huffman symbol's low nibble (s) is greater than 1 while not in an EOB-run state. The condition `s !== 1` inside the `else` branch of state 0 is the exact guard.
Common situations: A progressively-encoded JPEG produced by a buggy or non-standard encoder, or scan data corrupted after the first (DC) pass. Often seen in PDFs that re-encode images with custom progressive pipelines or in images damaged by copy/transport.
Related errors
- invalid huffman sequence
- missing required Quantization Table.
- JpegImage.parse - unknown marker: ${fileMarker.toString(16)}
- JpegImage.parse - no frame data found.
- SOI not found
AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13).
Data as JSON: /api/errors/d6fd2de3a8c88815.
Report an issue: GitHub.