{"record":{"id":"e387f6ba8f56fd69","repo":"mozilla/pdf.js","slug":"transport-destroyed","errorCode":null,"errorMessage":"Transport destroyed","messagePattern":"Transport destroyed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/display/api.js","lineNumber":3037,"sourceCode":"      pageNumber <= 0 ||\n      pageNumber > this.pagesMapper.pagesNumber\n    ) {\n      return Promise.reject(new Error(\"Invalid page request.\"));\n    }\n    const pageIndex = pageNumber - 1;\n    const newPageIndex = this.pagesMapper.getPageId(pageNumber) - 1;\n\n    const cachedPromise = this.#pagePromises.get(pageIndex);\n    if (cachedPromise) {\n      return cachedPromise;\n    }\n    const promise = this.messageHandler\n      .sendWithPromise(\"GetPage\", {\n        pageIndex: newPageIndex,\n      })\n      .then(pageInfo => {\n        if (this.destroyed) {\n          throw new Error(\"Transport destroyed\");\n        }\n        if (pageInfo.refStr) {\n          this.#pageRefCache.set(pageInfo.refStr, newPageIndex);\n        }\n\n        const page = new PDFPageProxy(\n          pageIndex,\n          pageInfo,\n          this,\n          this.pagesMapper,\n          this._params.pdfBug\n        );\n        this.#pageCache.set(pageIndex, page);\n        return page;\n      });\n    this.#pagePromises.set(pageIndex, promise);\n    return promise;\n  }","sourceCodeStart":3019,"sourceCodeEnd":3055,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/display/api.js#L3019-L3055","documentation":"A generic Error in WorkerTransport.getPage: after the sendWithPromise('GetPage') resolves with pageInfo, the transport checks this.destroyed before constructing the PDFPageProxy. If the document was destroyed while the GetPage round-trip was in flight, the page cannot be created and the promise rejects with 'Transport destroyed'.","triggerScenarios":"Calling doc.getPage(n) and then calling loadingTask.destroy() (or triggering transport destruction) before the page info returns; navigating away mid-page-load; cancelling a multi-page prefetch loop.","commonSituations":"SPA route changes during page prefetch; thumbnail generation interrupted by close; rapid document switches in a viewer.","solutions":["Await destroy() before issuing or relying on getPage results, or stop requesting pages once destroy begins.","Treat 'Transport destroyed' as an expected rejection when the user navigates away.","Guard prefetch loops with an 'isAlive' flag set false on destroy."],"exampleFix":"let alive = true;\nloadingTask.promise.then(d => {\n  for (let i = 1; i <= d.numPages && alive; i++) {\n    d.getPage(i).catch(e => {\n      if (/Transport destroyed/.test(e.message)) return;\n      throw e;\n    });\n  }\n});\n// on teardown:\nalive = false;\nawait loadingTask.destroy();","handlingStrategy":"try-catch","validationCode":"// Guard prefetch loops with an alive flag.\nlet alive = true;\nasync function prefetch(doc) {\n  for (let i = 1; i <= doc.numPages && alive; i++) {\n    await doc.getPage(i).catch(e => {\n      if (/Transport destroyed/.test(e.message)) return;\n      throw e;\n    });\n  }\n}\n// teardown:\nalive = false;\nawait loadingTask.destroy();","typeGuard":null,"tryCatchPattern":"try {\n  const page = await doc.getPage(n);\n} catch (e) {\n  if (/Transport destroyed/.test(e.message)) return null; // closed mid-request\n  throw e;\n}","preventionTips":["Track an 'alive' flag and stop calling getPage once destroy begins.","Await destroy() before starting a new document so in-flight pages settle.","Treat 'Transport destroyed' after navigation as expected."],"tags":["lifecycle","destroy","race-condition","getpage","transport"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}