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

  1. Decode the JPEG with a reference decoder (libjpeg-turbo) to confirm the progressive scan data is malformed.
  2. If you control encoding, ensure successive AC refinement scans only emit category 0/1 symbols.
  3. 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 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


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