Skip to content

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.

The PDF.js team provides a legacy build for compatibility with older environments:

typescript
// 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:

bash
# 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:

  1. Create pdfjs.d.ts (or add to existing declarations):
typescript
declare module 'pdfjs-dist/legacy/build/pdf.js';
  1. Update tsconfig.json:
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

javascript
// 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

  1. Environment Consistency: Use Node.js v18 LTS with legacy build for long-term support
  2. Worker Management: Always specify the worker source explicitly
  3. Version Pinning: Lock your pdfjs-dist version to prevent unexpected breaks
json
// package.json
{
  "dependencies": {
    "pdfjs-dist": "4.4.168"
  }
}
  1. Server vs Client: For server-side usage (like Astro endpoints), legacy build is mandatory with Node <22

Complete Working Example (Node.js/Astro)

typescript
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.