Error Fix: Cannot read properties of undefined (reading 'createElement') in a PDF.js Web Worker
TLDR
Invokingpage.render() inside a Web Worker thread crashes with TypeError: Cannot read properties of undefined (reading 'createElement') because PDF.js defaults to DOMCanvasFactory, which calls document.createElement('canvas'). To resolve this inside workers, pass CanvasFactory: OffscreenCanvasFactory (capital 'C', class constructor) in getDocument() options.
getDocument() Option Passing Form | Evaluation Result | Web Worker Execution Outcome |
|---|---|---|
canvasFactory: { create() {...} } | Ignored (Lowercase key ignored) | Crashes (document.createElement error) |
CanvasFactory: new Factory() | Ignored / Throws (new applied to instance) | Crashes (Factory is not a constructor) |
CanvasFactory: OffscreenCanvasFactory | Passes (new creates class instance) | Passes ($100\%$ Worker execution success) |
Defect diagnostics & source analysis
Inside PDF.js source code:
// PDF.js internal constructor lookup
const CanvasFactory = src.CanvasFactory || DefaultCanvasFactory;
// PDF.js instantiates factory internally this._canvasFactory = new CanvasFactory({ ownerDocument, enableHWA });
If src.CanvasFactory is omitted, PDF.js falls back to DefaultCanvasFactory (DOMCanvasFactory), calling document.createElement('canvas') and failing inside workers.
Remediation code pattern
Implement OffscreenCanvasFactory and gate initialization on OffscreenCanvas availability:
export class OffscreenCanvasFactory {
create(width, height) {
const canvas = new OffscreenCanvas(width, height);
return { canvas, context: canvas.getContext('2d') };
}
reset(canvasAndCtx, width, height) { canvasAndCtx.canvas.width = width; canvasAndCtx.canvas.height = height; }
destroy(canvasAndCtx) { canvasAndCtx.canvas.width = 0; canvasAndCtx.canvas.height = 0; canvasAndCtx.canvas = null; canvasAndCtx.context = null; } }
export async function loadPdfDocumentInWorker(pdfBytes) { const canvasFactoryOption = typeof OffscreenCanvas !== 'undefined' ? { CanvasFactory: OffscreenCanvasFactory } : {};
return pdfjsLib.getDocument({ data: pdfBytes, ...canvasFactoryOption }).promise; }
Rule of thumb: Pass CanvasFactory as an uninstantiated class constructor to PDF.js when initializing rendering inside Web Workers.