From 4822f03b224db2aa9227550678b8e583ecb9bae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Fri, 23 Oct 2026 19:47:22 +0200 Subject: [PATCH 1/2] Suppress more errors due to closed documents Closing/switching the document in the viewer will cause multiple tasks to fail. Other code paths already have `if (pdfDocument !== this.pdfDocument) return;` checks to know if the document has been changed after an async step, but it was missing in some places leading to errors being logged in the console. This commit adds the check in those places. --- web/pdf_viewer.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 2773526db9c72..67add3c030dbc 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -1196,6 +1196,10 @@ class PDFViewer { } }, reason => { + if (pdfDocument !== this.pdfDocument) { + return; // The document was closed while loading the page. + } + console.error( `Unable to get page ${pageNum} to initialize viewer`, reason @@ -1208,6 +1212,10 @@ class PDFViewer { if (pageNum % PagesCountLimit.PAUSE_EAGER_PAGE_INIT === 0) { await promise; + + if (pdfDocument !== this.pdfDocument) { + break; // The document was closed, stop fetching more pages. + } } } }); @@ -1228,6 +1236,10 @@ class PDFViewer { } }) .catch(reason => { + if (pdfDocument !== this.pdfDocument) { + return; // The document was closed while the first page loaded. + } + console.error("Unable to initialize viewer", reason); this._pagesCapability.reject(reason); @@ -2139,13 +2151,17 @@ class PDFViewer { if (pageView.pdfPage) { return pageView.pdfPage; } + const { pdfDocument } = this; try { - const pdfPage = await this.pdfDocument.getPage(pageView.id); + const pdfPage = await pdfDocument.getPage(pageView.id); if (!pageView.pdfPage) { pageView.setPdfPage(pdfPage); } return pdfPage; } catch (reason) { + if (pdfDocument !== this.pdfDocument) { + return null; // The document was closed while the page was loading. + } console.error("Unable to get page for page view", reason); return null; // Page error -- there is nothing that can be done. } @@ -2195,8 +2211,10 @@ class PDFViewer { ); if (pageView) { - this.#ensurePdfPageLoaded(pageView).then(() => { - this.renderingQueue.renderView(pageView); + this.#ensurePdfPageLoaded(pageView).then(pdfPage => { + if (pdfPage !== null) { + this.renderingQueue.renderView(pageView); + } }); return true; } From a8fd84c62e180d04d14575c9a6bac682e64b4268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Mon, 2 Nov 2026 16:19:26 +0100 Subject: [PATCH 2/2] Reject `pagesCapability` when the document is closed This is so that those promises don't remain pending forever, and their callers can clean up associated resources. --- web/app.js | 6 ++++++ web/pdf_scripting_manager.js | 6 +++++- web/pdf_viewer.js | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/web/app.js b/web/app.js index ed900ce309435..b23b159b909c5 100644 --- a/web/app.js +++ b/web/app.js @@ -1837,6 +1837,9 @@ const PDFViewerApplication = { this.setInitialView(hash); }) .catch(() => { + if (pdfDocument !== this.pdfDocument) { + return; // The document was closed while initializing. + } // Ensure that the document is always completely initialized, // even if there are any errors thrown above. this.setInitialView(); @@ -1857,6 +1860,9 @@ const PDFViewerApplication = { this._initializeAutoPrint(pdfDocument, openActionPromise); }, reason => { + if (pdfDocument !== this.pdfDocument) { + return; // The document was closed while the pages loaded. + } this._documentError("pdfjs-loading-error", { message: reason.message }); } ); diff --git a/web/pdf_scripting_manager.js b/web/pdf_scripting_manager.js index 8760fb9f4f94c..25b475c78cd95 100644 --- a/web/pdf_scripting_manager.js +++ b/web/pdf_scripting_manager.js @@ -361,7 +361,11 @@ class PDFScriptingManager { pdfViewer.currentPageNumber = value + 1; break; case "print": - await pdfViewer.pagesPromise; + try { + await pdfViewer.pagesPromise; + } catch { + break; // The document was closed, or failed to load. + } this.#eventBus.dispatch("print", { source: this }); break; case "println": diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 67add3c030dbc..0fc63d3ec5eb7 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -30,6 +30,7 @@ /** @typedef {import("./l10n.js").L10n} L10n */ import { + AbortException, AnnotationEditorType, AnnotationEditorUIManager, AnnotationMode, @@ -915,6 +916,10 @@ class PDFViewer { if (this.pdfDocument) { this.eventBus.dispatch("pagesdestroy", { source: this }); + // Ensure that `pagesPromise` doesn't remain pending forever, if the + // document was closed before all pages were loaded. + this._pagesCapability.reject(new AbortException("Document was closed.")); + this._cancelRendering(); this._resetView();