Question

Why Puppeteer PDF generation not working on Windows?

I have this NodeJs app, trying to generate a PDF from HTML. It works on Mac, but not on Windows (times out). Here's the code.

const puppeteer = require('puppeteer');
const fs = require('fs');

const init = async () => {
    try {
        const browser = await puppeteer.launch({headless: true});
        const page = await browser.newPage();

        await page.setContent('<h1>Hello World</h1>');
        await page.emulateMediaType('screen');
        await page.pdf({
            path: 'hello-world.pdf',
            format: 'A4',
            printBackground: true,
            timeout: 0
        });

        console.log('PDF Generated');
        await browser.close();
        process.exit()

    } catch (error) {
        console.log(error)
    }
};

init()

after calling page.pdf method, it waits so long and times out. ProtocolError: Page.printToPDF timed out. Increase the 'protocolTimeout' setting in launch/connect calls for a higher timeout if needed.

But on my M1 MacBook Pro, it works like a charm.

Tried this on a Windows 11 VM (Parallels) and a couple of Windows 11 laptops. But No luck.

What am I doing wrong here? Do I need to add something else?

Thanks!

Node: v20.15.0

Puppeteer: ^22.12.1

 2  134  2
1 Jan 1970

Solution

 2

After a few hours I was able to find the issue.

After launching the browser with browser logging await puppeteer.launch({headless: true, dumpio:true}); it logged this:

[16848:6956:0703/000025.226:ERROR:sandbox_win.cc(913)] Sandbox cannot access executable. Check filesystem permissions are valid. See [URL]: Access is denied. (0x5)

DevTools listening on ws://[URL][16848:7356:0703/000025.488:ERROR:network_service_instance_impl.cc(600)] Network service crashed, restarting service.
[16848:6956:0703/000026.330:ERROR:sandbox_win.cc(913)] Sandbox cannot access executable. Check filesystem permissions are valid. See [URL]: Access is denied. (0x5)

so I was able to find adding args: ['--no-sandbox', '--disable-setuid-sandbox'] is a workaround but not recommended https://stackoverflow.com/a/53975412/9814969

const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); worked!

Seems to be that this is a common issue on Linux based systems but I was trying it on Windows. Therefore adding this as an answer

2024-07-02
ChethiyaKD

Solution

 2

Based on the io log from your own answer, I'm not sure if you were actually able to see the [URL] it prints to the console but it leads to this documentation of the Chromium Sandbox which specifies that you might have to set the required permissions yourself depending on your way of installation. This can be the case when using Puppeteer on Windows. This has also basically been copy-pasted into the Puppeteer Troubleshooting, which also provides a way how you can set the required permissions with icacls.

This is imo a safer way than just disabling the sandboxing alltogether. However, the SID used in the provided command S-1-15-2-1 results to ALL APPLICATION PACKAGES, which is pretty broad. This is why both docs mention that "in high security environments a more restrictive SID should be used such as one from the installer" (I'm pretty sure that the provided link to the installer is actually referencing the wrong LOC and it should actually lead to here). However, the Chromium Sandbox docs mention the ALL RESTRICTED APPLICATION PACKAGES SID (Windows 10 RS2 or higher), which doesn't show up in Microsoft's official list of "Well-Known SIDs" but is S-1-15-2-2.

Solution: This is why I think that, instead of disabling the Sandbox, it would be safer to grant the required permissions by executing the following command in CMD:

icacls %USERPROFILE%/.cache/puppeteer/chrome /grant *S-1-15-2-2:(OI)(CI)(RX)

Running cmd as an admin is not required (at least it wasn't for me). The path is where Puppeteer usually stores its chrome bins, but you might need to adjust it if you specified a different path in Puppeteer.

The thing is, S-1-15-2-2 is still a pretty broad SID, but I wasn't able to figure out a more narrow SID that would work. If you check the installer, you can see that it sets GENERIC_READ (GR) and FILE_DELETE_CHILD (DC) for the SID AUTHENTICATED_USERS, however this cannot be all because the LOC in "sandbox_win.cc" that throws your error actually checks for GENERIC_READ (GR) and GENERIC_EXECUTE (GE) (so (RX) in total). I'm pretty sure User SIDs and Group SIDs won't work. I think what would work would be a "Logon" SID starting with S-1-5-5-, but that would change every time. I'll play around a little more with the information found in this answer and edit this if I find a safer solution. Also, I'm not even sure why the package SIDs work, because they should only work for Windows Store apps, processes running in an App Container, or UWP. So it's definitely not a Windows Store app, I also checked with Process Explorer and the process in question doesn't run in an App Container. I couldn't make sure if Chromium on Windows is UWP.

2024-07-22
Fiddlesteaks