Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RuntimeError with WebAssembly in @react-pdf/yoga on Node.js Server #1572

Open
gino8080 opened this issue Feb 2, 2024 · 3 comments
Open

RuntimeError with WebAssembly in @react-pdf/yoga on Node.js Server #1572

gino8080 opened this issue Feb 2, 2024 · 3 comments

Comments

@gino8080
Copy link

gino8080 commented Feb 2, 2024

Hello,

I've encountered a critical issue while using @react-pdf/renderer in a Node.js Express server environment. The server crashes with a RuntimeError related to WebAssembly memory allocation when attempting to generate PDFs. The error message is as follows:

RuntimeError: Aborted(RangeError: WebAssembly.instantiate(): Out of memory: wasm memory). Build with -sASSERTIONS for more info.
    at w (/usr/app/node_modules/yoga-layout/binaries/wasm-async-node.js:14:73)
    at /usr/app/node_modules/yoga-layout/binaries/wasm-async-node.js:62:60

This error suggests that the WebAssembly module within yoga-layout, which is a dependency of @react-pdf/renderer, is running out of memory.

To Reproduce

  1. Set up a basic Express server that uses @react-pdf/renderer to generate PDFs.
  2. Trigger the PDF generation endpoint with the necessary data.
  3. The server crashes with the above RuntimeError after a few successful PDF generations.
    Expected Behavior:

The PDF generation should complete successfully without causing a server crash or running out of WebAssembly memory.

Actual Behavior:

The server crashes with a RuntimeError indicating that WebAssembly ran out of memory.

Additional Context:

The issue seems to occur after generating multiple PDFs, suggesting a potential memory leak or insufficient memory allocation for WebAssembly in the yoga-layout module.
Reducing the complexity of the PDF layout temporarily mitigates the issue but does not solve it entirely.
I would appreciate any insights or suggestions on how to resolve this issue. If there are any known workarounds or if additional information is needed, please let me know.

Environment:

Node.js version: v16.18.1
Express version: ^4.18.2
@react-pdf/layout": "3.10.3",
@react-pdf/renderer": "3.3.4",
Operating System: docker image

Thank you for your time and assistance.

@NickGerleman
Copy link
Contributor

NickGerleman commented Feb 2, 2024

This is going to be hard to diagnose without more information about the usage.

The Yoga wasm binary allows heap growth (

"SHELL:-s ALLOW_MEMORY_GROWTH=1"
) and provides methods to free nodes/configs.

Without knowing more, out of memory seems like the consuming library might not be freeing resources, or that there is an irregularly large tree.

@nicoburns
Copy link
Contributor

Not sure if this is relevant, but in my (browser based) benchmarking scripts where I was constructing, measuring and then destructing Yoga trees in a loop, I was hitting a similar crash. It took quite high iteration count (>10000) to hit it, but it was with a script that in theory shouldn't have increased heap size at all. This also occurred with a similar Taffy-based benchmark at similar iteration counts.

It could perhaps be due to heap fragmentation? Or immaturity of WASM implementations? Although I must admit that I haven't investigated this thoroughly enough to rule out user error.

As a workaround, if this is only occurring after repeated PDF generation, then you could try the following steps (in order):

  • Catch the exception
  • Deinitialise the WASM module
  • Reinitialise the WASM module
  • Retry your call into Yoga

@NickGerleman
Copy link
Contributor

I took a quick look at this, and other issues running into it: vercel/next.js#51870

I missed that this error happens during WASM environment instantiation. So, this error indicates that the WASM is being loaded into a new environment, and Node doesn't have enough memory to do that.

I am wondering if this scenario is somehow doing this loading more than once, or if maybe multiple processes are doing this, and running out of memory.

I went to double check if we have documented guarantees from Emscripten module that it is only loaded once on load call, but couldn't quickly verify. We are pushing out Yoga 3.0 now, which will cache the instance regardless.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants