Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Gate conversion on PDF.js’s loading promise. Call getDocument(), await its PDFDocumentLoadingTask.promise, and invoke conversion only after that promise resolves. If loading rejects, record the original error and return a failure for that input. Never continue with an undefined or partially initialized document.
The safe control flow
PDF.js loading and conversion are separate asynchronous stages. pdfjsLib.getDocument() returns a loading task; its promise resolves to a PDF document. The conversion stage must be downstream of that resolution.
async function loadAndConvert(pdfjsLib, input, convert) {
let loadingTask;
try {
loadingTask = pdfjsLib.getDocument({ data: input });
const pdf = await loadingTask.promise;
return await convert(pdf);
} catch (err) {
console.error("PDF load or conversion failed", err);
throw err;
}
}
This single try block is suitable when the caller only needs one failure path. The important property is the gate: convert(pdf) cannot run until a document exists. Re-throwing preserves the original exception for the caller, queue, or HTTP handler.
Keep load and conversion diagnostics separate
For production pipelines, separate catches identify which stage failed and allow a batch job to continue with other files.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →#1 Best Overall
async function processPdf(pdfjsLib, bytes, convert, logger) {
let pdf;
try {
const task = pdfjsLib.getDocument({ data: bytes });
pdf = await task.promise;
} catch (err) {
logger.error({ err, stage: "pdf-load" }, "Could not load PDF");
return { ok: false, stage: "pdf-load" };
}
try {
const output = await convert(pdf);
return { ok: true, output };
} catch (err) {
logger.error({ err, stage: "conversion" }, "Could not convert PDF");
return { ok: false, stage: "conversion" };
}
}
Do not replace the original error with a generic “conversion failed” message when loading was the real problem. Keep the error object, stage, input category, Node.js version, and PDF.js version in internal logs; exclude document contents, authorization headers, and other secrets.
Using try...catch and promise catches
Recommended: await inside try...catch
With an async function, a rejected loading promise is caught naturally:
async function load(pdfjsLib, bytes) {
try {
const task = pdfjsLib.getDocument({ data: bytes });
return await task.promise;
} catch (error) {
console.error({ stage: "pdf-load", code: error?.code }, error);
return null;
}
}
const pdf = await load(pdfjsLib, bytes);
if (!pdf) {
// Stop this input. Do not call the converter.
return;
}
await convert(pdf);
Returning null (or a typed result such as {ok:false}) makes the stop condition explicit. Avoid a catch that logs and then falls through to conversion.
Explicit .catch()
Promise chains work when every branch returns a value that the next stage checks:
Recommended Free Tools
const task = pdfjsLib.getDocument({ data: bytes });
const result = await task.promise
.then(pdf => ({ ok: true, pdf }))
.catch(error => ({ ok: false, stage: "pdf-load", error }));
if (!result.ok) {
logger.error(result, "PDF load failed");
return result;
}
return convert(result.pdf);
The two styles are equivalent if the rejection is observed and conversion is unreachable after failure. Do not mix an unhandled promise with a surrounding synchronous try...catch; a later rejection will bypass that catch.
Rank #2
Validate the input before calling PDF.js
Raw bytes
When your application already has the file, pass a Uint8Array (or compatible typed-array view) rather than converting binary data to base64. PDF.js documentation notes that base64 introduces extra memory overhead. A Node.js example using fs is:
import { readFile } from "node:fs/promises";
import * as pdfjsLib from "pdfjs-dist/legacy/build/pdf.mjs";
const bytes = new Uint8Array(await readFile("input.pdf"));
const task = pdfjsLib.getDocument({ data: bytes });
const pdf = await task.promise;
Check that the buffer is non-empty, came from the expected upload or object, and was not accidentally decoded as UTF-8 text. If you accept uploads, enforce size limits before allocating additional copies.
Remote URLs
A URL input causes PDF.js or your server to fetch bytes. Cross-origin browser requests require the remote server to permit access with CORS; where that is unavailable, fetch the file on your server (with appropriate SSRF protections) and pass the resulting typed array. A proxy also lets you validate status, content type, length, and redirects before PDF.js sees the data.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsconst response = await fetch(pdfUrl, { redirect: "follow" });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const contentType = response.headers.get("content-type") || "";
if (!contentType.includes("pdf")) {
throw new Error(`Unexpected content type: ${contentType}`);
}
const bytes = new Uint8Array(await response.arrayBuffer());
const pdf = await pdfjsLib.getDocument({ data: bytes }).promise;
Apply host allowlists, timeout and maximum-size controls to prevent a remote URL from turning the converter into an SSRF or memory-exhaustion endpoint.
Why a damaged PDF may still load
PDF.js attempts to recover usable pages, content, or fonts from some corrupted files. Therefore, corruption does not always produce a rejected loading promise. Make decisions from the actual result: a resolved document can still have missing pages or rendering problems, while a rejection must stop the conversion path. If your output requires every page, inspect page access and fail explicitly when a required page cannot be obtained.
Rank #3
const pdf = await pdfjsLib.getDocument({ data: bytes }).promise;
if (pdf.numPages < 1) {
throw new Error("Loaded PDF contains no pages");
}
for (let pageNumber = 1; pageNumber <= pdf.numPages; pageNumber++) {
const page = await pdf.getPage(pageNumber);
await convertPage(page);
}
Runtime, package, and worker compatibility
Check the deployed versions
The current PDF.js FAQ lists Node.js 22+ as mostly supported, with limited automated testing and some missing features. Treat that as version-sensitive documentation status, not a guarantee for every release. Record the exact Node.js and pdfjs-dist versions from the deployment that failed and reproduce with those versions.
Fix API/worker mismatches
If the error mentions an API and worker version mismatch, use exactly matching PDF.js API and worker files. A stale cached worker or a worker loaded from a different CDN release can trigger this failure. Pin the package version, clear build and browser caches where applicable, and configure the worker from that same installed version. Do not mix a locally installed API with an unrelated CDN worker.
Node-specific defaults
PDF.js uses Node-oriented defaults for options such as disableFontFace, isOffscreenCanvasSupported, and isImageDecoderSupported; they can differ from web defaults and can vary by release. Do not infer a bug from an assumed default. Check the API reference and your installed version, then set an option deliberately when your conversion environment needs it.
Operational error handling
Return structured results
For queues and batch conversion, return a stable result instead of treating every failure as an exception at the top level:
function safeError(error) {
return {
name: error?.name,
code: error?.code,
message: error?.message
};
}
async function convertOne(pdfjsLib, bytes, convert, logger) {
try {
const pdf = await pdfjsLib.getDocument({ data: bytes }).promise;
return { ok: true, value: await convert(pdf) };
} catch (error) {
logger.error({ stage: "pdf-load-or-conversion", error: safeError(error) });
return { ok: false, error: safeError(error) };
}
}
Node.js notes that error.message can change across versions; use error.code to identify Node errors when available, while retaining the complete error internally for stack information.
Rank #4
Cancellation and timeouts
Do not leave a rejected or abandoned task running indefinitely in a web request. Use an AbortController for the fetch that supplies bytes, enforce an application deadline around loading and conversion, and release references to large buffers after a job finishes. A timeout should be reported as the stage that exceeded it, not mislabeled as a successful conversion.
Troubleshooting checklist
- “Conversion” runs after a load error: inspect the catch block for a fall-through path; return or throw immediately and test the gate with a deliberately invalid byte array.
- Unhandled promise rejection: ensure the promise returned by
task.promiseis awaited or returned from the function that owns the catch. - Invalid or empty input: verify the upload buffer, avoid UTF-8 conversion, and pass a
Uint8Array. - Remote URL fails only in a browser: inspect CORS headers or fetch through a controlled server-side proxy.
- Corrupt file behaves inconsistently: remember that PDF.js may recover; validate the pages and content your converter actually needs.
- Worker mismatch: align API and worker versions exactly and remove stale cached assets.
- Node runtime issue: compare the deployed runtime with the documented Node.js support status and test the installed PDF.js release, not a different package version.
- Logs expose sensitive data: record metadata and sanitized error details, never raw PDF bytes, URLs containing credentials, or document text.
Or skip the browser setup
If the goal is a clean image or PDF of a web page rather than converting a local PDF, ScreenshotNeo provides a single API request. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
See the ScreenshotNeo API documentation for all options, including full-page and element captures, device and retina settings, PDF paper size and margins, custom CSS and JavaScript, waits, request blocking, headers and cookies, geolocation, caching, signed links, asynchronous webhooks, bulk capture, and usage reporting.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
One thousand screenshots per month are free with no card. Paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Should I catch errors around getDocument() or around task.promise?
Catch the promise rejection from task.promise; wrapping the task creation as well protects against synchronous argument or setup errors.
Can I convert when PDF.js returns a document for a damaged file?
Yes, if your converter can tolerate recovered content. Check required pages and assets explicitly because a resolved load does not prove that every object is intact.
Is a URL input better than bytes?
Neither is universally better. Bytes let your server validate and control the fetch; URLs may be simpler but introduce CORS, redirects, remote availability, and security concerns.
Frequently Asked Questions
What is the essential fix for a PDF conversion load error?
Await PDF.js’s loading-task promise and enter conversion only after it resolves; on rejection, return or throw without calling the converter.
Why does a corrupted PDF sometimes not reject?
PDF.js can recover usable pages, content, or fonts from some damaged files, so validate the resolved document instead of assuming corruption always causes a load failure.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
What should a worker mismatch error prompt me to check?
Ensure the PDF.js API and worker come from exactly the same version and remove stale cached worker files.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




