{"record":{"id":"c18114cd968810aa","repo":"mozilla/pdf.js","slug":"pdfworker-create-the-worker-is-being-destroyed","errorCode":null,"errorMessage":"PDFWorker.create - the worker is being destroyed.\nPlease remember to await `PDFDocumentLoadingTask.destroy()`-calls.","messagePattern":"PDFWorker\\.create - the worker is being destroyed\\.\nPlease remember to await `PDFDocumentLoadingTask\\.destroy\\(\\)`-calls\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/display/api.js","lineNumber":2360,"sourceCode":"    this.#webWorker?.terminate();\n    this.#webWorker = null;\n\n    PDFWorker.#workerPorts.delete(this.#port);\n    this.#port = null;\n\n    this.#messageHandler?.destroy();\n    this.#messageHandler = null;\n  }\n\n  /**\n   * @param {PDFWorkerParameters} params - The worker initialization parameters.\n   * @returns {PDFWorker}\n   */\n  static create(params) {\n    const cachedPort = this.#workerPorts.get(params?.port);\n    if (cachedPort) {\n      if (cachedPort._pendingDestroy) {\n        throw new Error(\n          \"PDFWorker.create - the worker is being destroyed.\\n\" +\n            \"Please remember to await `PDFDocumentLoadingTask.destroy()`-calls.\"\n        );\n      }\n      return cachedPort;\n    }\n    return new PDFWorker(params);\n  }\n\n  /**\n   * The current `workerSrc`, when it exists.\n   * @type {string}\n   */\n  static get workerSrc() {\n    if (GlobalWorkerOptions.workerSrc) {\n      return GlobalWorkerOptions.workerSrc;\n    }\n    throw new Error('No \"GlobalWorkerOptions.workerSrc\" specified.');","sourceCodeStart":2342,"sourceCodeEnd":2378,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/display/api.js#L2342-L2378","documentation":"A generic Error from PDFWorker.create: the requested port maps to a cached PDFWorker whose _pendingDestroy flag is set, meaning destroy() was called on it but has not finished. Reusing a half-destroyed worker would race the teardown. The message explicitly reminds the caller to await PDFDocumentLoadingTask.destroy().","triggerScenarios":"Calling PDFWorker.create({port}) (or getDocument with that port via GlobalWorkerOptions.workerPort) after a previous worker.destroy() on the same port without awaiting its completion; rapid create/destroy churn on a shared port.","commonSituations":"SPA teardown/remount cycles that destroy and immediately recreate a worker; forgetting that destroy() is asynchronous; fire-and-forget cleanup handlers.","solutions":["Always await worker.destroy() (and any loadingTask.destroy() that owns it) before creating a new PDFWorker on the same port.","Sequence teardown and recreation in an async function so the next create runs after destroy resolves.","If you cannot await, allocate a fresh port/Worker for the new PDFWorker instead of reusing."],"exampleFix":"// before\nworker.destroy(); // not awaited\npdfjsLib.PDFWorker.create({ port }); // throws\n\n// after\nawait worker.destroy();\npdfjsLib.PDFWorker.create({ port });","handlingStrategy":"validation","validationCode":"// Ensure the cached worker is not mid-destroy before reuse.\nconst cached = pdfjsLib.PDFWorker._workerPorts?.get?.(port);\nif (cached && cached._pendingDestroy) {\n  throw new Error('Await the previous worker.destroy() first');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always await loadingTask.destroy() / worker.destroy() before reusing a port.","Sequence teardown and recreation in an async flow.","Allocate a fresh port if you cannot await the prior destroy."],"tags":["worker","lifecycle","async","destroy","port"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}