{"record":{"id":"8f7efad543723df5","repo":"mozilla/pdf.js","slug":"startcleanup-page-page-pagenumber-is-currently","errorCode":null,"errorMessage":"startCleanup: Page ${page.pageNumber} is currently rendering.","messagePattern":"startCleanup: Page (.+?) is currently rendering\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/display/api.js","lineNumber":3221,"sourceCode":"  getMarkInfo() {\n    return this.messageHandler.sendWithPromise(\"GetMarkInfo\", null);\n  }\n\n  getRawData(data) {\n    return this.messageHandler.sendWithPromise(\"GetRawData\", data);\n  }\n\n  async startCleanup(keepLoadedFonts = false) {\n    if (this.destroyed) {\n      return; // No need to manually clean-up when destruction has started.\n    }\n    await this.messageHandler.sendWithPromise(\"Cleanup\", null);\n\n    for (const page of this.#pageCache.values()) {\n      const cleanupSuccessful = page.cleanup();\n\n      if (!cleanupSuccessful) {\n        throw new Error(\n          `startCleanup: Page ${page.pageNumber} is currently rendering.`\n        );\n      }\n    }\n    this.commonObjs.clear();\n    if (!keepLoadedFonts) {\n      this.fontLoader.clear();\n    }\n    this.#methodPromises.clear();\n    this.filterFactory.destroy(/* keepHCM = */ true);\n    TextLayer.cleanup();\n  }\n\n  cachedPageNumber(ref) {\n    if (!isRefProxy(ref)) {\n      return null;\n    }\n    const refStr = ref.gen === 0 ? `${ref.num}R` : `${ref.num}R${ref.gen}`;","sourceCodeStart":3203,"sourceCodeEnd":3239,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/display/api.js#L3203-L3239","documentation":"Thrown by PDFDocumentProxy.startCleanup() when at least one cached PDFPageProxy reports cleanup() === false, meaning it is still rendering (its rendering state is not INITIAL). startCleanup wants every page idle so it can safely release common objects, fonts and method promises; an in-flight page would be corrupted by the teardown that follows.","triggerScenarios":"Calling startCleanup() while a page.render() task is still running; calling it right after render() without awaiting the returned promise; cancelled-but-not-yet-settled render tasks.","commonSituations":"Viewer teardown during scroll/zoom where the previous render is mid-flight; aggressive memory management triggered by a low-memory event before the render promise resolved; tests that forget to await renderTask.promise.","solutions":["Await (or cancel and await) every renderTask.promise before calling startCleanup().","Use renderTask.cancel() then await renderTask.promise.catch(() => {}) to force pages back to INITIAL.","If cleanup is opportunistic, wrap startCleanup() in try/catch and retry once renders settle."],"exampleFix":"// before\nawait page.render({ canvasContext, viewport });\nawait pdfDocument.startCleanup();\n\n// after\nconst task = page.render({ canvasContext, viewport });\nawait task.promise;\nawait pdfDocument.startCleanup();\n\n// or, when tearing down mid-render:\ntask.cancel();\nawait task.promise.catch(() => {});\nawait pdfDocument.startCleanup();","handlingStrategy":"validation","validationCode":"// ensure every cached page is idle before cleanup\nconst busy = [...pdf._transport._pageCache.values?.() ?? []];\n// simpler: track your own render tasks and await them\nawait Promise.allSettled(activeRenderTasks.map(t => t.promise));\nawait pdf.startCleanup();","typeGuard":"null","tryCatchPattern":"try {\n  await pdf.startCleanup();\n} catch (e) {\n  if (e.message.startsWith('startCleanup:')) { /* retry after renders settle */ }\n  else throw e;\n}","preventionTips":["Keep a registry of every renderTask you start; cancel/await them before cleanup.","Call cleanup only when the viewer is in a known-idle state.","In tests, always await task.promise before the teardown assertion."],"tags":["rendering","cleanup","lifecycle"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}