mozilla/pdf.js · error · FormatError

unexpected EOF in bcmap

Error message

unexpected EOF in bcmap

What it means

Thrown by BinaryCMapStream.readNumber() (binary_cmap.js:78) when getByte() returns a negative value while decoding a variable-length, 7-bit-encoded integer from a binary CMap (.bcmap) stream. Binary CMaps are the packed CMap resources PDF.js fetches from cMapUrl to map character codes for CJK (Chinese/Japanese/Korean) fonts. The error means the byte stream ended before a complete integer could be read, so the resource is truncated or corrupt.

Source

Thrown at src/core/binary_cmap.js:78

class BinaryCMapStream extends Stream {
  tmpBuf = new Uint8Array(MAX_ENCODED_NUM_SIZE);

  constructor(data) {
    super(
      /* arrayBuffer = */ data,
      /* start = */ 0,
      /* length = */ data.length,
      /* dict = */ null
    );
  }

  readNumber() {
    let n = 0;
    let last;
    do {
      const b = this.getByte();
      if (b < 0) {
        throw new FormatError("unexpected EOF in bcmap");
      }
      last = !(b & 0x80);
      n = (n << 7) | (b & 0x7f);
    } while (!last);
    return n;
  }

  readSigned() {
    const n = this.readNumber();
    return n & 1 ? ~(n >>> 1) : n >>> 1;
  }

  readHex(num, size) {
    num.set(this.getBytes(size + 1));
  }

  readHexNumber(num, size) {
    let last;

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Verify cMapUrl points to a complete, matching PDF.js CMap distribution (the 'external/bcmaps' folder of the same release) and that cMapPacked is left at its default true.
  2. Confirm the .bcmap file is served whole: fetch it directly, compare byte length to the source file, and check for proxy/CDN truncation or double-gzip.
  3. If a 404/HTML page is being served for the CMap, fix the URL/path so the correct binary resource resolves.
  4. Update PDF.js and its bundled CMaps to the same version so the bcmap format the reader expects matches the files shipped.

Example fix

// before: cMapUrl missing or wrong, packed CMap truncated
getDocument({ data, /* cMapUrl omitted */ });

// after: ship the matching packed CMap set and reference it
import { GlobalWorkerOptions } from 'pdfjs-dist';
getDocument({
  data,
  cMapUrl: 'https://mycdn.example.com/pdfjs/cmaps/',
  cMapPacked: true, // default; ensures .bcmap files are fetched as binary
}).promise;
Defensive patterns

Strategy: validation

Validate before calling

// Before getDocument, ensure packed CMaps are reachable and complete.
// Ship the cmaps folder from the SAME pdfjs-dist release you bundle.
const cMapUrl = new URL('cmaps/', import.meta.url).href; // local, complete copy
const params = { data, cMapUrl, cMapPacked: true };
// Optionally HEAD-check a known bcmap to confirm the dir is served:
// fetch(new URL('GBK-EUC-H.bcmap', cMapUrl), { method: 'HEAD' })
//   .then(r => { if (!r.ok) throw new Error('CMap dir unreachable'); });

Try / catch

// CMap errors are caught internally and degrade font mapping; if you must surface them,
// wrap the rendering task and check for FormatError-like messages.
try {
  await page.render({ canvasContext, viewport }).promise;
} catch (err) {
  if (/bcmap|EOF/i.test(err?.message)) {
    console.warn('CJK CMap resource problem; text may not map correctly', err);
  } else throw err;
}

Prevention

When it happens

Trigger: BinaryCMapReader.process() parses a .bcmap file (loaded via cMapUrl for a PDF using CJK fonts) whose data is shorter than its encoding declares, or whose leading bytes were consumed and a subsequent record expected more bytes than remain. Concretely: getByte() returning -1 (EOF) inside the do/while loop of readNumber() while a 7-bit varint is only partially read.

Common situations: cMapUrl pointing at an incomplete/edited CMap distribution; a CDN or reverse proxy truncating the .bcmap response (wrong Content-Length, gzip issue, partial range request); the fetch landing an HTML 404/500 page whose body is then parsed as binary CMap bytes; an outdated bcmap format shipped with a newer PDF.js build.

Related errors


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