| name | pdfjs-errors-document |
| description | Use when handling PDF document loading failures, password-protected PDFs, corrupt files, or missing CMap/font data. Prevents unhandled exceptions by covering all PDF.js error types and their recovery patterns. Covers InvalidPDFException, MissingPDFException, PasswordException, network/CORS errors, CJK font issues, and corrupt PDF recovery strategies. Keywords: InvalidPDFException, MissingPDFException, PasswordException, CMap, CORS, corrupt PDF, PDF won't load, broken PDF, can't open PDF, password protected, PDF error.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires pdfjs-dist 5.x. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
pdfjs-errors-document
Quick Reference
Document Error Types
| Exception / Error | Likely Cause | Severity |
|---|
InvalidPDFException | Corrupt file, not a PDF, truncated download | Critical |
MissingPDFException | 404, wrong URL, file deleted | Critical |
PasswordException (code NEED_PASSWORD) | PDF is password-protected, no password provided | High |
PasswordException (code INCORRECT_PASSWORD) | Wrong password provided | High |
UnknownErrorException | Unexpected internal error during parsing | High |
| CORS / Network error | Cross-origin fetch blocked, mixed content | Critical |
| Missing CMap data | CJK characters render as blank or tofu | Medium |
| Font loading failure | Missing standardFontDataUrl, broken embedded fonts | Medium |
| Memory error / OOM | Extremely large PDF exceeding browser memory | High |
Critical Warnings
ALWAYS wrap getDocument().promise in a try/catch -- document loading can throw any of the exception types above, and unhandled rejections cause blank pages with no user feedback.
ALWAYS check the name property of caught errors to distinguish between InvalidPDFException, MissingPDFException, PasswordException, and UnknownErrorException -- each requires a different recovery strategy.
NEVER swallow document loading errors with an empty catch block -- the user sees a blank page with no indication of what went wrong.
ALWAYS configure cMapUrl and set cMapPacked: true when loading PDFs that may contain CJK (Chinese, Japanese, Korean) text -- without CMaps, CJK characters render as blank rectangles.
ALWAYS set standardFontDataUrl when using pdfjs-dist 5.x -- PDF.js needs access to standard font data files for proper text rendering of PDFs that reference standard 14 fonts.
NEVER retry a PasswordException with the same password -- it will fail again. ALWAYS prompt the user for a new password before retrying.
Diagnostic Decision Tree
PDF document fails to load?
|
+-- InvalidPDFException
| +-- File is 0 bytes? -> Download/upload failed, retry transfer
| +-- File starts with "%PDF"? -> PDF is corrupt or truncated, re-obtain file
| +-- File is actually HTML (404 page)? -> Server returned error page, fix URL
| +-- File is a different format (DOCX, image)? -> Not a PDF, convert first
|
+-- MissingPDFException
| +-- URL returns 404? -> Fix the URL path
| +-- File was deleted? -> Handle gracefully, show "file not found" message
| +-- Redirect to login page? -> Handle authentication before loading PDF
| +-- Using relative URL? -> Use absolute URL or correct base path
|
+-- PasswordException
| +-- code === PasswordResponses.NEED_PASSWORD? -> Prompt user for password
| +-- code === PasswordResponses.INCORRECT_PASSWORD? -> Show "wrong password", reprompt
| +-- Programmatic access needed? -> Pass password in getDocument({ password })
|
+-- Network / CORS error
| +-- Mixed content (HTTP PDF on HTTPS page)? -> Serve PDF over HTTPS
| +-- Cross-origin without CORS headers? -> Add CORS headers on PDF server
| +-- Proxy available? -> Route PDF through same-origin proxy
| +-- Fetch fails entirely? -> Check network, show offline message
|
+-- CJK text missing / blank characters
| +-- cMapUrl not set? -> Set cMapUrl to cmaps directory path
| +-- cMapPacked not true? -> Add cMapPacked: true to getDocument options
| +-- CMap files not deployed? -> Copy cmaps/ from pdfjs-dist to public dir
|
+-- Font rendering issues
| +-- standardFontDataUrl not set? -> Set path to standard_fonts directory
| +-- Embedded font broken? -> PDF issue, not fixable in viewer
| +-- Font files not deployed? -> Copy standard_fonts/ from pdfjs-dist
|
+-- Memory error / crash on large PDF
| +-- PDF > 100 MB? -> Enable range requests (disableRange: false)
| +-- Many high-res images? -> Reduce rendering scale
| +-- Mobile device? -> Limit concurrent page renders
|
+-- UnknownErrorException
+-- Check err.message for details -> May contain specific parser error
+-- Reproducible with other PDFs? -> Likely a code issue, not PDF issue
+-- Only this PDF? -> Likely a corrupt or unusual PDF structure
Essential Fixes
Fix 1: InvalidPDFException -- Corrupt or Non-PDF File
Error: InvalidPDFException: Invalid PDF structure
Cause: The loaded data is not a valid PDF. Common when a server returns an HTML error page instead of the PDF file, or the file is truncated.
import { getDocument, GlobalWorkerOptions } from "pdfjs-dist";
GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.mjs",
import.meta.url
).toString();
async function loadPdfSafely(source: string | ArrayBuffer) {
try {
const doc = await getDocument(
typeof source === "string" ? { url: source } : { data: source }
).promise;
return doc;
} catch (err: unknown) {
if (err instanceof Error && err.name === "InvalidPDFException") {
throw new Error(
"The file is not a valid PDF. It may be corrupt, truncated, " +
"or the server returned an error page instead of the PDF file."
);
}
throw err;
}
}
Prevention: ALWAYS validate that the server response has Content-Type: application/pdf before passing data to getDocument(). If loading from user upload, check that the file starts with the %PDF magic bytes.
Fix 2: MissingPDFException -- File Not Found
Error: MissingPDFException: Missing PDF file.
Cause: The URL returned a 404 or the fetch failed entirely.
import { getDocument, GlobalWorkerOptions } from "pdfjs-dist";
GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.mjs",
import.meta.url
).toString();
async function loadPdfWithNotFoundHandling(url: string) {
try {
return await getDocument({ url }).promise;
} catch (err: unknown) {
if (err instanceof Error && err.name === "MissingPDFException") {
throw new Error(
`PDF file not found at "${url}". ` +
"Verify the URL is correct and the file exists on the server."
);
}
throw err;
}
}
Fix 3: PasswordException -- Password-Protected PDF
Error: PasswordException with code: PasswordResponses.NEED_PASSWORD
Cause: The PDF is encrypted and requires a password to open.
import {
getDocument,
GlobalWorkerOptions,
PasswordResponses,
} from "pdfjs-dist";
GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.mjs",
import.meta.url
).toString();
async function loadPasswordProtectedPdf(
url: string,
promptForPassword: () => Promise<string | null>
) {
try {
return await getDocument({ url }).promise;
} catch (err: unknown) {
if (!(err instanceof Error) || err.name !== "PasswordException") {
throw err;
}
const typedErr = err as Error & { code: number };
if (typedErr.code === PasswordResponses.NEED_PASSWORD ||
typedErr.code === .) {
password = ();
(!password) ();
{
({ url, password }).;
} (: ) {
(retryErr &&
retryErr. === ) {
();
}
retryErr;
}
}
err;
}
}
Fix 4: CORS / Network Errors
Error: Failed to fetch or Access to fetch blocked by CORS policy
Cause: The PDF is hosted on a different origin without CORS headers, or the page uses HTTPS while the PDF is served over HTTP (mixed content).
import { getDocument, GlobalWorkerOptions } from "pdfjs-dist";
GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.mjs",
import.meta.url
).toString();
async function loadPdfViaProxy(externalUrl: string) {
const proxyUrl = `/api/pdf-proxy?url=${encodeURIComponent(externalUrl)}`;
return await getDocument({ url: proxyUrl }).promise;
}
async function loadPdfWithFetch(url: string) {
const response = await fetch(url, {
mode: "cors",
credentials: "omit",
});
if (!response.ok) {
throw new Error(`Failed to fetch PDF: ${response.status} ${response.statusText}`);
}
data = response.();
({ data }).;
}
Fix 5: Missing CMap Data for CJK Text
Error: CJK characters appear as blank rectangles or tofu characters.
Cause: PDF.js needs CMap (Character Map) files to decode CJK-encoded text. Without them, characters in Chinese, Japanese, or Korean PDFs render incorrectly.
import { getDocument, GlobalWorkerOptions } from "pdfjs-dist";
GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.mjs",
import.meta.url
).toString();
const doc = await getDocument({
url: "/path/to/document.pdf",
cMapUrl: new URL(
"pdfjs-dist/cmaps/",
import.meta.url
).toString(),
cMapPacked: true,
}).promise;
Prevention: ALWAYS set cMapUrl and cMapPacked: true in getDocument() options. The CMap files are included in the pdfjs-dist/cmaps/ directory. For production, copy the cmaps/ directory to your public assets folder.
Fix 6: Font Loading Failures
Error: Text renders with wrong glyphs, missing characters, or falls back to default fonts.
Cause: PDF.js needs standard font data files for PDFs that reference the standard 14 PDF fonts without embedding them.
import { getDocument, GlobalWorkerOptions } from "pdfjs-dist";
GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.mjs",
import.meta.url
).toString();
const doc = await getDocument({
url: "/path/to/document.pdf",
standardFontDataUrl: new URL(
"pdfjs-dist/standard_fonts/",
import.meta.url
).toString(),
cMapUrl: new URL(
"pdfjs-dist/cmaps/",
import.meta.url
).toString(),
cMapPacked: true,
}).promise;
Prevention: Production-Ready Document Loading
import {
getDocument,
GlobalWorkerOptions,
PasswordResponses,
} from "pdfjs-dist";
import type { PDFDocumentProxy } from "pdfjs-dist";
GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.mjs",
import.meta.url
).toString();
interface LoadOptions {
url: string;
password?: string;
onPasswordRequired?: () => Promise<string | null>;
onError?: (type: string, message: string) => void;
}
async function loadDocument(options: LoadOptions): Promise<PDFDocumentProxy> {
const { url, password, onPasswordRequired, onError } = options;
try {
return await getDocument({
url,
password,
cMapUrl: (, ..).(),
: ,
: (
,
..
).(),
}).;
} (: ) {
(!(err )) err;
(err.) {
:
onError?.(, );
err;
:
onError?.(, );
err;
: {
typedErr = err & { : };
(onPasswordRequired &&
(typedErr. === . ||
typedErr. === .)) {
pw = ();
(pw) ({ ...options, : pw });
onError?.(, );
}
err;
}
:
onError?.(, );
err;
}
}
}
Reference Links
Official Sources