parallax/jsPDF · error · Error

Unknown gif block: 0x" + buf[p - 1].toString(16)

Error message

Unknown gif block: 0x" + buf[p - 1].toString(16)

What it means

Thrown by the GIF parser's main block loop in GifReader when it reads a block-introducer byte that is not one of the three legal GIF block types (0x21 extension, 0x2c image descriptor, 0x3b trailer). The parser has already passed the GIF87a/89a header check, so this fires when the body stream is corrupt or truncated. omggif uses it as a hard stop because it cannot safely resynchronize on an unknown block.

Source

Thrown at src/libs/omggif.js:591

          height: h,
          has_local_palette: has_local_palette,
          palette_offset: palette_offset,
          palette_size: palette_size,
          data_offset: data_offset,
          data_length: p - data_offset,
          transparent_index: transparent_index,
          interlaced: !!interlace_flag,
          delay: delay,
          disposal: disposal
        });
        break;

      case 0x3b: // Trailer Marker (end of file).
        no_eof = false;
        break;

      default:
        throw new Error("Unknown gif block: 0x" + buf[p - 1].toString(16));
        break;
    }
  }

  this.numFrames = function() {
    return frames.length;
  };

  this.loopCount = function() {
    return loop_count;
  };

  this.frameInfo = function(frame_num) {
    if (frame_num < 0 || frame_num >= frames.length)
      throw new Error("Frame index out of range.");
    return frames[frame_num];
  };

View on GitHub (pinned to a3930ce03a)

Solutions

  1. Validate the input is a Uint8Array/ArrayBuffer of plausible GIF length and re-fetch the source if it may be truncated.
  2. Wrap `new GifReader(buf)` in try/catch and reject the image / fall back to a placeholder on failure.
  3. If you control the bytes, re-encode the GIF with a mainstream tool (gifsicle/ImageMagick) to strip exotic blocks before embedding in a PDF via jsPDF's processGIF89A.
  4. Confirm the file magic: bytes 0-5 must be 47 49 46 38 (GIF8) before attempting a parse.

Example fix

// before
var reader = new GifReader(anyBytes);
reader.decodeAndBlitFrameRGBA(0, pixels);

// after
function isGif(b) {
  return b && b.length >= 6 && b[0]===0x47 && b[1]===0x49 && b[2]===0x46 && b[3]===0x38;
}
if (!isGif(anyBytes)) throw new Error('not a GIF');
try {
  var reader = new GifReader(anyBytes);
  reader.decodeAndBlitFrameRGBA(0, pixels);
} catch (e) {
  console.warn('GIF parse failed, skipping image', e.message);
}
Defensive patterns

Strategy: validation

Validate before calling

function isValidGifBytes(b) {
  if (!(b instanceof Uint8Array) && !Array.isArray(b)) return false;
  if (b.length < 13) return false;
  // GIF8 magic
  return b[0]===0x47 && b[1]===0x49 && b[2]===0x46 && b[3]===0x38;
}
if (!isValidGifBytes(anyBytes)) {
  throw new Error('Input is not valid GIF data');
}

Type guard

function isGifBytes(b) {
  return (b instanceof Uint8Array || Array.isArray(b)) &&
    b.length >= 13 &&
    b[0]===0x47 && b[1]===0x49 && b[2]===0x46 && b[3]===0x38;
}

Try / catch

var reader;
try {
  reader = new GifReader(anyBytes);
} catch (e) {
  if (/Unknown gif block/.test(e.message)) {
    console.warn('Corrupt or unsupported GIF, skipping:', e.message);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing truncated, corrupted, or non-GIF bytes that happen to start with a valid 'GIF8' header into `new GifReader(buf)`. Also a malformed GIF where an extension sub-block length is wrong, desynchronizing the cursor so the next read lands on a random byte instead of a valid introducer.

Common situations: Loading a GIF over HTTP that was cut off mid-transfer; feeding a PNG/JPEG that was mislabeled as GIF but whose early bytes coincidentally matched; passing a Uint8Array whose view is offset or length is wrong; a GIF with a vendor-specific extension the strict parser refuses to skip.

Related errors


AI-assisted analysis of parallax/jsPDF@a3930ce03a (2026-08-13). Data as JSON: /api/errors/a881e0da554874c1. Report an issue: GitHub.