It will not run
Failed to launch the browser process
The process throws on startup with a message about failing to launch, often followed by a line about a missing shared library or an unexpected exit. It works on your laptop and fails in the container.
What is actually happening
A headless browser is not a self-contained binary. It links against a couple of dozen system libraries for fonts, graphics and audio, and a slim base image has essentially none of them. The download succeeds, the binary is there, and it cannot start.
Confirming it is this and not something that looks like it
Run the browser binary directly inside the container. It will name the first missing library, which is more useful than the wrapper's error.
The fix
Install the dependency set in the image, or stop shipping a browser. The dependency list is long, changes between browser versions, and differs by base distribution, which is why this specific error has outlived every attempt to document it. Calling a render over HTTP removes the whole class of problem: there is no binary in your image to fail.
# The image on the left is what a render needs. The image on the right is what
# an application needs. They are not the same image, and maintaining the first
# one is ongoing work rather than a one-time setup.
FROM node:22-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates fonts-liberation libasound2 libatk-bridge2.0-0 \
libatk1.0-0 libatspi2.0-0 libcairo2 libcups2 libdbus-1-3 libdrm2 \
libgbm1 libglib2.0-0 libnspr4 libnss3 libpango-1.0-0 libx11-6 \
libxcomposite1 libxdamage1 libxext6 libxfixes3 libxkbcommon0 libxrandr2 \
&& rm -rf /var/lib/apt/lists/*If that was not it
These produce the same symptom often enough to be worth ruling out before assuming the fix above did not work.
- Alpine, where the glibc-linked browser build will not run at all and needs the musl package instead
- An ARM host with an x86 browser build, or the reverse
- PUPPETEER_SKIP_DOWNLOAD set in CI, so the binary was never fetched
- A read-only filesystem, which the browser needs somewhere writable to work around
Frequently asked
Does this happen with every rendering engine?
The behaviour behind it is not specific to one tool. A headless browser is not a self-contained binary. Anything rendering HTML to a paged medium has to make the same decision, so the fix travels with you if you change how the render happens.
Will this show up as an error in my logs?
Yes, this one surfaces as a thrown error or a failed status, which is why it is at least findable. The harder half is that the message often names the call that was in flight rather than the thing that actually failed.
Related failures
Problems people arrive at from the same starting point, or mistake for this one.
libnss3.so: cannot open shared object file
This is the previous error with the first missing library named.
Navigation timeout of 30000 ms exceeded
The default wait condition is the network going idle, and something on the page is keeping it busy: an analytics beacon, a font request to a host that is not responding, a polling request, or an ad script.
Protocol error (Page.printToPDF): Target closed
The tab crashed, and by far the most common reason is memory.
Chromium does not fit in an AWS Lambda deployment package
A full browser build is several hundred megabytes and the unzipped package limit is 250MB.
PDF generation runs out of memory
Two multiplying factors.
CSS for paged documents, and what actually works
Which parts of the paged media specification a browser-based render implements.
Everything that goes wrong, by category
The full list, grouped by where in the pipeline it breaks.
Paste your markup and see the rendered document, without signing up.