react-pdf icon indicating copy to clipboard operation
react-pdf copied to clipboard

sendWithPromise("GetPage", ... null causing an error

Open jdc-cunningham opened this issue 2 years ago • 32 comments

Before you start - checklist

  • [X] I followed instructions in documentation written for my React-PDF version
  • [X] I have checked if this bug is not already reported
  • [X] I have checked if an issue is not listed in Known issues
  • [X] If I have a problem with PDF rendering, I checked if my PDF renders properly in PDF.js demo

Description

I use two instances of react-pdf. The main viewer is using a functional component and the second one is a class-based that's not visible. It's a background renderer to produce pdf thumbnail previews. This has been working fine since 2021.

After recently pulling down 5.7.2 my background PDF render throws an error just before it renders. After reverting to 5.7.1 it's working fine.

  • load 1 PDF it's fine
  • load another PDF it breaks

I put error handlers on the <Document... and <Page... I have onSourceError, onLoadError, onRendeError handlers but those don't fire, the error above happens.

I will continue investigating/work on reproducible code unfortunately what I'm working on is not public.

Attached below are the images of the error.

Steps to reproduce

Setup a class-based react-pdf component.

Pass down a file path (by props), it renders.

Pass down another file path

Expected behavior

The PDFs render as the sources are updated.

Actual behavior

Fails to render the PDF/produces the errors below

When this error happens it crashes the entire react app eg. blank screen.

err-1

err-2

Additional information

No response

Environment

  • Browser (if applicable): Chrome
  • React-PDF version: 5.7.2
  • React version: ^4.42.0
  • Webpack version (if applicable): ^16.3.0

jdc-cunningham avatar Apr 01 '22 05:04 jdc-cunningham

Looks like it's this bit...

https://github.com/mozilla/pdf.js/blob/a3e34002cbc8870e6a863bd3ded045c842b6de07/src/display/api.js#L2874-L2877

Interesting.

Could it be the changes from #947?

wojtekmaj avatar Apr 01 '22 10:04 wojtekmaj

Thanks for the quick response.

I loaded it up on a staging site/back to 5.7.2. This shows a gap in our testing to test this far (more than one document loaded in the background).

I did look to see if there's a direct call relevant there. I added an expanded callstack trace attached below, I think your hunch is right.

It could be that I'm using it wrong too. Here's a gist on the background renderer class-based component I have. This is a child of another component managing its state so the active file comes down as a prop. Also the functional instance is a sibling/same depth as this functional one.

Maybe it's the async getDocPageImg call?

expanded-stack

jdc-cunningham avatar Apr 01 '22 14:04 jdc-cunningham

Am facing the same issue, hoping for this to get fixed soon. Thanks!

sueyz avatar May 20 '22 15:05 sueyz

Not a solution but I've capped the react-pdf version in my project to 5.7.1 for the time being.

jdc-cunningham avatar May 20 '22 16:05 jdc-cunningham

We've hit the same situation with an application using react 16.14. The first PDF seemed to load fine, but remounting or changing to a new PDF would result in errors.

Was able to workaround by rolling back to 5.7.1 as others have. Don't have much else to add to previous reports, but did want to note that the root cause was one of a number of different errors on different subcomponents from Page down. For future search-ability, figured it was worth adding examples from a dev bundle created with 5.7.2:

Failed prop type: The prop 'page.commonObjs._objs' is marked as required in 'PageCanvasInternal', but its value is 'undefined'. 

Failed prop type: The prop 'page.commonObjs._objs' is marked as required in 'TextLayerInternal', but its value is 'undefined'

PerryAJ avatar Jul 19 '22 01:07 PerryAJ

This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this issue will be closed in 14 days.

github-actions[bot] avatar Oct 24 '22 00:10 github-actions[bot]

I`m having the same problem. Is this being addressed?

FabricioK avatar Oct 26 '22 13:10 FabricioK

Does anyone have a reproducible CodeSandbox repo? I'm especially interested if this is still reproducible in v6.

wojtekmaj avatar Nov 09 '22 21:11 wojtekmaj

We have this issue for the following flow:

  1. Render without file (see No PDF file specified.)
  2. File is selected => ok
  3. Render without file (see No PDF file specified.)
  4. File is selected again => JS error Downgrade to 5.7.1 didn't help, was another issue. Made a workaround: just to add Key for Document component that contains file name, then everything seems to work fine because of re-initialization of component. 6.x branch is not usable due to issue #1043 (thanks for keeping API compatible, but webpack 4 seems to be not compatible anymore without some re-configuration)

illusdolphin avatar Dec 08 '22 09:12 illusdolphin

We're having the same issue on v6.2.0. Reverting to v5 fixes it. We haven't been able to reproduce locally but it does happen in production and we're getting many errors. We re-render with different files many times during the component's lifetime.

image image

ldiqual avatar Dec 17 '22 00:12 ldiqual

This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this issue will be closed in 14 days.

github-actions[bot] avatar Mar 20 '23 00:03 github-actions[bot]

I think we solved the issue. It's mostly in the user-code together with internal logic of component. Demo code is simple and does not handle file change situation. Solving for us was easy - just make page number of pages to render to 0 at the moment file is changed. Sample code below (not sure about 100% compiling, but the idea should be clear. For sure this might be solved on component level, then it needs to ignore pages when loading is in progress.

`import React, { useState } from 'react'; import { Document, Page } from 'react-pdf';

function MyApp() { const [numPages, setNumPages] = useState(0); const [fileName, setFileName] = useState('somefile.pdf'); const [pageNumber, setPageNumber] = useState(1);

function onDocumentLoadSuccess({ numPages }) { setNumPages(numPages); // <== here is the issue #1 - we save page number of file, but in case it's changed, we know about new number only after it's loaded, before doc is loaded, this value is wrong }

function setNewFile(){ //file change event setNumPages(0); setFileName('newfile.pdf'); }

return ( <div onClick={setNewFile}> <Document file={fileName} onLoadSuccess={onDocumentLoadSuccess}> {Array.from(new Array(numPages), (_, index) => ( <Page key={index} pageNumber={index + 1} /> ), )} { /* here we render all pages of file, but if new file is being loaded, we try loading pages that are not available */ } </Document>

Page {pageNumber} of {numPages}

); }`

illusdolphin avatar Mar 20 '23 09:03 illusdolphin

I found a related issue in react-pdf-viewer that was due to reusing a destroyed worker:

  • Issue: https://github.com/react-pdf-viewer/react-pdf-viewer/issues/417
  • Fix: https://github.com/react-pdf-viewer/react-pdf-viewer/pull/424

It seems that we're encountering this bug when changing loading blob A then blob B very quickly. My guess is that when page 1 of blob A gets to load, the worker for blob A is already destroyed because blob B is now loading.

ldiqual avatar Mar 27 '23 19:03 ldiqual

Just add useAsync or your own implementation when generating the url, the @ldiqual response is correctly, it changes from a to b very quickly and the worker is not setted.

Also, if you gonna using some reactivity, i recommend using debounce in function that change url also

I was used react-pdf/@reneder and change to jsPDF and the issue continued, and this is what i did

const render = useAsync(async () => {
    const url = doc.output("blob");
    return url;
  }, []);

Here is a code reference how to fix react-pdf/@renderer if someone is using https://github.com/diegomura/react-pdf-site/tree/master/src/components/Repl

pedroferreira37 avatar May 18 '23 04:05 pedroferreira37

Weird. I've only now started getting this error when trying to migrate to v7.

MattL75 avatar Jun 02 '23 14:06 MattL75

Hello, I encountered the exact same problem after updating from v6.2.2 to v7.1.1. I solved it controlling the page rendering. I allow my app to render the page only if the document has been successfully loaded (onDocumentLoadSuccess).

cattale93 avatar Jun 08 '23 09:06 cattale93

hey - can you add an example how did you resolved it ?@cattale93

WoldemortRules avatar Jun 15 '23 05:06 WoldemortRules

The error can be temporarily bypassed by using:

useEffect(() => {
    setTimeout(() => {
      setIsRenderPdf(true)
    }, 500)
  }, [])
isRenderPdf ? 
<Document 
  key={pdfUrl} 
  file={pdfUrl} >
</Document>

luxiangqiang avatar Jul 24 '23 11:07 luxiangqiang

hey - can you add an example how did you resolved it ?@cattale93

Hello @WoldemortRules

<Document
      className={'PDFDoc'}
      file={fileLocation}
      onLoadSuccess={this.onDocumentLoadSuccess}  // the pdf is rendered only based on a specific state in this function.
      onSourceError={this.onLoadError}
      onLoadError={this.onLoadError}
      renderMode={'canvas'}
      onItemClick={this.goToPage}
      options={{ cMapUrl: 'cmaps/',  cMapPacked: true,}}
>

According to the documentation onLoadSuccess -> Function called when the document is successfully loaded.

cattale93 avatar Jul 24 '23 19:07 cattale93

Same issue here with v6.0.3. Any news on a fix for this?

We can do conditional rendering, but as this worked in V5, it would be nice if this worked in React 18 versions of react-pdf.

MasNotsram avatar Aug 03 '23 11:08 MasNotsram

I am facing the same issue when using 7.3.3.

jiangxiaoqiang avatar Aug 22 '23 06:08 jiangxiaoqiang

It seems I solved the problem. You only need to prevent Document rerender. The above reason is because rerender causes pdfjs to reload pdf with an error.

little-buddy avatar Sep 22 '23 05:09 little-buddy

I only got this error when I resized the screen using the responsive dev tool, here is my call stack

Call Stack
WorkerTransport.getOptionalContentConfig
node_modules\pdfjs-dist\build\pdf.js (2481:0)
PDFPageProxy.render
node_modules\pdfjs-dist\build\pdf.js (1385:0)
drawPageOnCanvas
node_modules\react-pdf\dist\esm\Page\PageCanvas.js (68:0)
commitHookEffectListMount
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (20002:0)
commitHookPassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22055:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22160:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22271:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22271:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22157:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22271:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22271:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22157:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22271:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22271:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22157:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22271:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22271:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22157:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22157:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22271:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22157:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22271:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22157:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22157:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22157:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22157:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22271:0)
recursivelyTraversePassiveMountEffects
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22138:0)
commitPassiveMountOnFiber
node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (22157:0)

huypham1411 avatar Oct 20 '23 04:10 huypham1411

My issue was solved by @illusdolphin. My exact error is not the as sendWithPromise() but pdf Cannot read properties of null (reading 'sendWithStream') But he gave me an idea. So here's the solution:

function onDocumentLoadSuccess(nextNumPages) {
  setNumPages(nextNumPages ?? 0);
}

So you just test the nextNumPage.

jhunexjun avatar Oct 24 '23 09:10 jhunexjun

step 1

<Document key={1} file={playUrl} onLoadSuccess={onDocumentLoadSuccess}

step 2

` const onDocumentLoadSuccess = (...args) => { const info = args[0]; setnumPages(info?.numPages??0) setIsRenderPdf(true)//设置状态

}`

step 3

{isRenderPdf&&new Array(10).fill('').map((cur, index) => ( <Page key={index} pageNumber={index + 1} renderAnnotationLayer={false} renderTextLayer={false} width={window.innerWidth} renderMode='canvas' /> ))}

name-undef1ned avatar Nov 20 '23 05:11 name-undef1ned

For me it worked after simply wrapping my Pdf Component with React.memo.

export default React.memo(PdfViewerComponent)

Puetz avatar Nov 21 '23 14:11 Puetz

For anybody still struggling, I got it to work on our side by using the method from this comment on a closed duplicate of this issue.

I'm using Next.js

cp node_modules/react-pdf/node_modules/pdfjs-dist/build/pdf.worker.js public/pdf.worker.js

Then, within your app where you'd like to setup the worker:

import { pdfjs } from 'react-pdf';

pdfjs.GlobalWorkerOptions.workerSrc = "/pdf.worker.js"

Honestly, I'm not totally sure why this worked. So, if anybody has a better understanding definitely feel free to reply. I'd be curious. Hope this helps!

TJohn2017 avatar Dec 09 '23 01:12 TJohn2017

For anybody still struggling, I got it to work on our side by using the method from this comment on a closed duplicate of this issue.

I'm using Next.js

cp node_modules/react-pdf/node_modules/pdfjs-dist/build/pdf.worker.js public/pdf.worker.js

Then, within your app where you'd like to setup the worker:

import { pdfjs } from 'react-pdf';

pdfjs.GlobalWorkerOptions.workerSrc = "/pdf.worker.js"

Honestly, I'm not totally sure why this worked. So, if anybody has a better understanding definitely feel free to reply. I'd be curious. Hope this helps!

Hi, I'm using Nextjs too and I also read the relative post about this issue but I don't understand this part

Copy react-pdf/node_modules/pdfjs-dist/build/pdf.worker.js to public

the react-pdf is inside the node_modules so this make me a bit confuse, hope you can help me, appreciate

huypham1411 avatar Dec 19 '23 04:12 huypham1411

For anybody still struggling, I got it to work on our side by using the method from this comment on a closed duplicate of this issue. I'm using Next.js cp node_modules/react-pdf/node_modules/pdfjs-dist/build/pdf.worker.js public/pdf.worker.js Then, within your app where you'd like to setup the worker:

import { pdfjs } from 'react-pdf';

pdfjs.GlobalWorkerOptions.workerSrc = "/pdf.worker.js"

Honestly, I'm not totally sure why this worked. So, if anybody has a better understanding definitely feel free to reply. I'd be curious. Hope this helps!

Hi, I'm using Nextjs too and I also read the relative post about this issue but I don't understand this part

Copy react-pdf/node_modules/pdfjs-dist/build/pdf.worker.js to public

the react-pdf is inside the node_modules so this make me a bit confuse, hope you can help me, appreciate

So, this method didn't actually end up resolving my issue. It made it less likely to occur, and we didn't see it for a bit but since making this post I've had the same issue a handful more times now. If anybody is able to find a true solution I'd really appreciate it.

If you'd still like to try that method you should see that react-pdf has a node_modules inside of it, despite it being inside of your project's node_modules. The full filepath should be node_modules/react-pdf/node_modules/pdfjs-dist/build/pdf.worker.js from the base of your Nextjs project.

TJohn2017 avatar Dec 22 '23 19:12 TJohn2017

我在添加自定义cMapUrl的时候也报这个错,之后把option给缓存就不会有这个问题了。

  const opt = useMemo(() => {
    return {
      cMapUrl: '/bcmaps/',
      cMapPacked: true,
    };
  }, []);

...

  return (
      <Document  options={opt}>
        {...}
      </Document>

  );

Adermi avatar Mar 07 '24 09:03 Adermi