PDF integration throws `Cannot read properties of null (reading 'getDownloadInfo')` with PDF.js ≥ 4.5 when the client loads before a document is open
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 83/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- javascript
- Ambito
- frontend
Direzione di ricerca
Inizia in src/annotator/integrations/pdf-metadata.ts, in corrispondenza di isPDFDownloaded(), e leggi come il listener documentloaded gestisce un risultato false. Riproduci il problema con PDF.js 4.5 o versioni successive avviando il client prima di aprire un documento. Poi conferma che il caso del documento null non provoca più un rifiuto e che il visualizzatore carica le annotazioni dopo l’apertura di un PDF.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Summary
PDFMetadata (src/annotator/integrations/pdf-metadata.ts) dereferences PDFViewerApplication.pdfDocument as soon as PDFViewerApplication.initializedPromise resolves. With PDF.js ≥ 4.5, where PDFViewerApplication.downloadComplete no longer exists (removed in mozilla/pdf.js#18463), that is the only code path. PDF.js resolves initializedPromise before it opens a document, so pdfDocument is still null whenever the client boots before the document is open. isPDFDownloaded() then throws, getUri() and getMetadata() reject, the sidebar never receives the document info and stays on its loading spinner. No annotation is loaded, and nothing is logged apart from the uncaught rejection.
The fallback added in #6541 assumed a document is already open (the bookmarklet case). Whether pdfDocument can be unset was raised in that review, and a follow-up issue was announced there, but I could not find one. The symptom is also mentioned in passing in #6784 ("Intermittently I have seen an error about a getDownloadInfo property …").
Steps to reproduce
Tested on 2026-11-08 with client 1.1769.0 (the build served by https://hypothes.is/embed.js) in Chrome 151, headless.
- Unzip a PDF.js generic viewer release, for example
pdfjs-6.5.438-dist.zip. - In
web/viewer.html, load the client with the page, right after the viewer's own module, and remove (or widen) the viewer'sContent-Security-Policymeta tag so the client can load:<script src="viewer.mjs" type="module"></script> <script src="https://hypothes.is/embed.js" async></script> - Serve the directory (for example
python3 -m http.server) and openweb/viewer.html?file=(an emptyfile, so the viewer starts without a document) with the console open. - Open a PDF through the viewer's file picker, or run
PDFViewerApplication.open({ url: 'compressed.tracemonkey-pldi-09.pdf' })in the console.
Observed with PDF.js 4.5.136 and 6.5.438: at step 3 the console shows
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'getDownloadInfo')
annotator.bundle.js
At step 4 the document renders, but the sidebar keeps spinning, lists nothing, and no highlight appears (0 <hypothesis-highlight> elements for the TraceMonkey paper, which has about 200 annotations in the Public group).
Expected, and observed with PDF.js 4.4.168 and the same steps: no error; after step 4 the sidebar lists the 199 public annotations and the highlights anchor (786 <hypothesis-highlight> elements).
With ?file=<pdf> instead of an empty file, the outcome depends on a race: the client works if PDF.js finishes opening the document before the client's PDFIntegration is constructed, and fails as above otherwise. In our deployment (client and viewer served from the same host, a 17-page PDF) it failed every time; locally, with the 1 MB TraceMonkey PDF and the client coming from the CDN, it usually works. That is presumably the intermittent error seen in #6784. Hypothesis's own pdfjs-init.js (this repo's dev-server, via, the browser extension, pdf.js-hypothes.is) also injects the client right after initializedPromise and only then calls PDFViewerApplication.open(), so those viewers hit the same race once they move past PDF.js 4.4.
Versions
| PDF.js | PDFViewerApplication.downloadComplete |
Client 1.1769.0 booting before the document is open |
|---|---|---|
| 3.11.174 … 4.4.168 | present | works (tested: 4.4.168) |
| 4.5.136 … 6.5.438 | removed in mozilla/pdf.js#18463, merged 2024-07-20 | TypeError, no annotations (tested: 4.5.136, 6.5.438) |
Presence checked in web/viewer.mjs of the release zips: 3.11.174, 4.0.379, 4.2.67, 4.3.136 and 4.4.168 define it; 4.5.136, 4.6.82, 4.7.76, 4.8.69, 4.9.155, 4.10.38, 5.0.375, 5.2.133, 5.4.394 and 6.5.438 do not.
Where
isPDFDownloaded() in src/annotator/integrations/pdf-metadata.ts, unchanged on main (a7b7400):
async function isPDFDownloaded(app: PDFViewerApplication): Promise<boolean> {
if (app.downloadComplete !== undefined) {
return app.downloadComplete;
}
await app.pdfDocument.getDownloadInfo(); // pdfDocument is null until PDFViewerApplication.load()
return true;
}
On the PDF.js side, PDFViewerApplication.run() awaits initialize(), which resolves initializedPromise, and only then calls open(). pdfDocument is assigned in load(), once getDocument() has resolved; until then it is null.
Suggested fix
Treat a null pdfDocument as "not downloaded yet", so the existing documentloaded listener in the PDFMetadata constructor takes over:
if (app.downloadComplete !== undefined) {
return app.downloadComplete;
}
if (!app.pdfDocument) {
// Viewer initialized, but no document opened yet (PDF.js >= 4.5).
return false;
}
await app.pdfDocument.getDownloadInfo();
return true;
PDF.js ≥ 4.5 still dispatches documentloaded after getDownloadInfo() resolves and the first page has rendered, so the fallback keeps the semantics of the old downloadComplete flag. Embedders can work around the problem today by loading the client only after the viewer's documentinit or documentloaded event, which is what we do.
- Lingua principale
- Mustache
- Stelle
- 743
- Fork
- 227
- Merge medio
- 6m
- PR unite (30g)
- 1
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di hypothesis/client
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 52/100
hypothesis/client#7586 ·
-
Common anti-FOUC styling technique hides sidebar with `hypothesis-sidebar {visibility: hidden}`Aperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 48/100
hypothesis/client#7498 ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
hypothesis/client#7341 ·
-
accessibility
Difficoltà 3/5 1-2 giorni Idoneità per principianti 42/100
hypothesis/client#7315 ·
-
accessibility
Difficoltà 5/5 Più di una settimana Idoneità per principianti 30/100
hypothesis/client#7314 ·
Tutte le issue di hypothesis/client
Issue simili
-
deepseek good first issue roadmap
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
LibreChat-AI/LibreChat#17915 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 86/100
fingerprintjs/fingerprintjs#1235 ·
-
Labor 09 - CSS: fájlnevekAperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 90/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 86/100
storytold/craft-libs#723 ·
I maintainer di solito rispondono entro 1 giorno