Resolving "Promise.withResolvers is not a function" in pdfjs-dist
Problem Statement
When using pdfjs-dist
in Node.js (like in an Astro server-side application) to extract text from PDF files, you may encounter this error:
Promise.withResolvers is not a function
The error typically occurs when:
- Using PDF.js in a Node.js environment
- Running on Node.js versions prior to v22
- Using newer builds of
pdfjs-dist
that rely on modern JavaScript features
The core issue is that Promise.withResolvers
was added in Node.js 22 and isn't available in earlier versions. Your extraction code might look correct, but fails due to this compatibility issue.
Recommended Solutions
Solution 1: Use the Legacy Build (Recommended)
The PDF.js team provides a legacy build for compatibility with older environments:
// Replace this:
// import * as pdfjsLib from "pdfjs-dist";
// With legacy import
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.js';
// Use legacy worker
pdfjsLib.GlobalWorkerOptions.workerSrc =
"../../node_modules/pdfjs-dist/legacy/build/pdf.worker.js";
export const contentExtractor = async (
arrayBufferPDF: ArrayBuffer
): Promise<string> => {
// Existing extraction logic remains unchanged
};
Key points
- Uses compatibility build without modern features
- Works with Node.js versions 18+
- Maintains all PDF.js functionality
Solution 2: Upgrade Node.js
If you can update your environment, upgrade to Node.js v22+ which supports Promise.withResolvers
:
# Using nvm
nvm install 22
nvm use 22
# Verify version
node -v # Should show v22.x or higher
Solution 3: Add TypeScript Declaration (For Legacy Build)
If using TypeScript with the legacy build, add this declaration:
- Create
pdfjs.d.ts
(or add to existing declarations):
declare module 'pdfjs-dist/legacy/build/pdf.js';
- Update
tsconfig.json
:
{
"compilerOptions": {
// ...other options
"typeRoots": [
"./node_modules/@types",
"./@types", // Custom declarations directory
"./" // Include root directory
]
}
}
Why These Solutions Work
Legacy Build Approach
The PDF.js legacy build:
- Uses ES5-compatible syntax
- Doesn't rely on modern features like
Promise.withResolvers
- Maintains full PDF parsing functionality
- Is officially supported by Mozilla (PDF.js docs)
Node Version Upgrade
Promise.withResolvers
became standard in:
- Node.js v22.0.0+ (Release notes)
- Modern browsers (Chrome 119+, Firefox 121+)
Alternative: Browser Polyfill (Client-Side Only)
WARNING
This solution only works in browser environments, not Node.js server-side
// Polyfill for Promise.withResolvers
if (typeof Promise.withResolvers === 'undefined') {
Promise.withResolvers = function () {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
};
}
// Configure PDF.js worker
pdfjsLib.GlobalWorkerOptions.workerSrc =
"https://unpkg.com/pdfjs-dist@4.4.168/legacy/build/pdf.worker.min.mjs";
Best Practices
- Environment Consistency: Use Node.js v18 LTS with legacy build for long-term support
- Worker Management: Always specify the worker source explicitly
- Version Pinning: Lock your pdfjs-dist version to prevent unexpected breaks
// package.json
{
"dependencies": {
"pdfjs-dist": "4.4.168"
}
}
- Server vs Client: For server-side usage (like Astro endpoints), legacy build is mandatory with Node <22
Complete Working Example (Node.js/Astro)
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.js';
// Path relative to your build output
pdfjsLib.GlobalWorkerOptions.workerSrc =
'../../node_modules/pdfjs-dist/legacy/build/pdf.worker.js';
export const extractPDFText = async (
buffer: ArrayBuffer
): Promise<string> => {
const pdf = await pdfjsLib.getDocument(buffer).promise;
let fullText = '';
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
const page = await pdf.getPage(pageNum);
const content = await page.getTextContent();
fullText += content.items.map((item: any) => item.str).join(' ');
}
return fullText;
};
TIP
pdfjs-dist
works with PDF byte arrays directly—no DOM or browser APIs required. Perfect for server-side processing in Astro.