{"record":{"id":"b69f847236626af9","repo":"mozilla/pdf.js","slug":"worker-was-destroyed","errorCode":null,"errorMessage":"Worker was destroyed","messagePattern":"Worker was destroyed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/display/api.js","lineNumber":407,"sourceCode":"      wasmUrl,\n      hasGPU: false, // Set below.\n    },\n  };\n  const transportParams = {\n    ownerDocument,\n    pdfBug,\n    styleElement,\n    enableHWA,\n    loadingParams: {\n      disableAutoFetch,\n      enableXfa,\n    },\n  };\n\n  Promise.all([worker.promise, gpuPromise])\n    .then(function ([, hasGPU]) {\n      if (worker.destroyed) {\n        throw new Error(\"Worker was destroyed\");\n      }\n\n      docParams.evaluatorOptions.hasGPU = hasGPU;\n\n      const workerIdPromise = worker.messageHandler.sendWithPromise(\n        \"GetDocRequest\",\n        docParams,\n        data ? [data.buffer] : null\n      );\n\n      let networkStream;\n      if (data) {\n        // The entire PDF was provided, no `networkStream` necessary.\n      } else if (rangeTransport) {\n        networkStream = new PDFDataTransportStream({\n          pdfDataRangeTransport: rangeTransport,\n          disableRange,\n          disableStream,","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/display/api.js#L389-L425","documentation":"A generic Error in getDocument's startup chain: after worker.promise resolves but before the GetDocRequest is sent, the worker was destroyed (worker.destroyed === true). The whole document load is aborted because there is no live worker to receive the request. This is a lifecycle error, not a data error.","triggerScenarios":"Calling loadingTask.destroy() or worker.destroy() during the brief window after worker setup but before GetDocRequest is dispatched; destroying a previously-started loading task and immediately starting a new one reusing the same worker; rapid mount/unmount in a SPA.","commonSituations":"React/Vue components that tear down before the async load resolves; navigation away from a page mid-load; cancelling a queued load after a timeout.","solutions":["Track the loading task and only destroy it once you no longer need the document; avoid destroying during load.","If cancelling is intentional, treat 'Worker was destroyed' as an expected rejection, not a bug.","Ensure you await any prior task.destroy() before starting a new getDocument that reuses the worker/port.","Use a separate PDFWorker per concurrent load instead of sharing one that gets torn down."],"exampleFix":"// before\nconst task = pdfjsLib.getDocument({ url });\nsetTimeout(() => task.destroy(), 50); // kills worker mid-handshake\n\n// after\nlet task = pdfjsLib.getDocument({ url });\ntry {\n  const doc = await task.promise;\n} catch (e) {\n  if (/Worker was destroyed/.test(e.message)) return; // expected cancel\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Do not start a load while a destroy is pending on the shared worker.\nif (worker.destroyed) {\n  throw new Error('Refusing to load: worker already destroyed');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const doc = await loadingTask.promise;\n} catch (e) {\n  if (/Worker was destroyed/.test(e.message)) return null; // expected cancel\n  throw e;\n}","preventionTips":["Await loadingTask.destroy() before reusing a worker/port.","Track loading tasks in a single owner so components cannot destroy out of order.","In SPAs, cancel via a flag instead of destroying during the handshake window."],"tags":["worker","lifecycle","destroy","race-condition","getdocument"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}