mozilla/pdf.js · error · Error
startCleanup: Page ${page.pageNumber} is currently rendering
Error message
startCleanup: Page ${page.pageNumber} is currently rendering. What it means
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.
Source
Thrown at src/display/api.js:3221
getMarkInfo() {
return this.messageHandler.sendWithPromise("GetMarkInfo", null);
}
getRawData(data) {
return this.messageHandler.sendWithPromise("GetRawData", data);
}
async startCleanup(keepLoadedFonts = false) {
if (this.destroyed) {
return; // No need to manually clean-up when destruction has started.
}
await this.messageHandler.sendWithPromise("Cleanup", null);
for (const page of this.#pageCache.values()) {
const cleanupSuccessful = page.cleanup();
if (!cleanupSuccessful) {
throw new Error(
`startCleanup: Page ${page.pageNumber} is currently rendering.`
);
}
}
this.commonObjs.clear();
if (!keepLoadedFonts) {
this.fontLoader.clear();
}
this.#methodPromises.clear();
this.filterFactory.destroy(/* keepHCM = */ true);
TextLayer.cleanup();
}
cachedPageNumber(ref) {
if (!isRefProxy(ref)) {
return null;
}
const refStr = ref.gen === 0 ? `${ref.num}R` : `${ref.num}R${ref.gen}`;View on GitHub (pinned to 5903d58d58)
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.
Example fix
// before
await page.render({ canvasContext, viewport });
await pdfDocument.startCleanup();
// after
const task = page.render({ canvasContext, viewport });
await task.promise;
await pdfDocument.startCleanup();
// or, when tearing down mid-render:
task.cancel();
await task.promise.catch(() => {});
await pdfDocument.startCleanup(); Defensive patterns
Strategy: validation
Validate before calling
// ensure every cached page is idle before cleanup const busy = [...pdf._transport._pageCache.values?.() ?? []]; // simpler: track your own render tasks and await them await Promise.allSettled(activeRenderTasks.map(t => t.promise)); await pdf.startCleanup();
Type guard
null
Try / catch
try {
await pdf.startCleanup();
} catch (e) {
if (e.message.startsWith('startCleanup:')) { /* retry after renders settle */ }
else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Image exceeded maximum allowed size and was removed.
- Unable to decode inline image: "${reason}".
- Type3 font load error: ${reason}
- Unknown PatternType: ${typeNum}
- Unknown PatternName: ${patternName}
AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13).
Data as JSON: /api/errors/8f7efad543723df5.
Report an issue: GitHub.