Puppeteer: Failed to Launch the Browser Process (Fixed)
Failed to launch the browser process in Puppeteer, step by step: we hit four different launch errors in one Docker image on Puppeteer 25 and fixed each one.
Error: Failed to launch the browser process is a wrapper. Puppeteer started Chrome, Chrome exited, and Puppeteer printed Chrome's stderr under the message. The real cause is in that stderr block, and it is almost always one of three things on Linux: a missing shared library (Code: 127), Chrome running as root with the sandbox on (Code: 1), or a sandbox the container does not allow (No usable sandbox!). Read the line under stderr: and jump to the matching section below.
This is a spoke of our Puppeteer screenshot guide. We started from a bare Debian slim image and fixed one error at a time. Each error below is copied from that run.
Tested on 2026-10-18 with Docker (OrbStack on macOS,
node:22-bookworm-slimlinux/amd64, Debian 12.15), Node 22, [email protected] (Chrome 155.0.8059.79). Version checks also ran [email protected] and @24.10.0.
The test script
import puppeteer from 'puppeteer'; const args = process.env.NO_SANDBOX ? ['--no-sandbox'] : []; const browser = await puppeteer.launch({ args }); try { const page = await browser.newPage(); await page.goto('https://example.com'); await page.screenshot({ path: '/tmp/example.png' }); console.log('OK', await browser.version()); } finally { await browser.close(); }
Stage 0: "Could not find Chrome" after a clean install
The first surprise came before any launch. npm i [email protected] exited with code 0, yet the script failed with:
Error: Could not find Chrome (ver. 155.0.8059.79). This can occur if either 1. you did not perform an installation before running the script (e.g. `npx puppeteer browsers install chrome`) or 2. your cache path is incorrectly configured (which is: /root/.cache/puppeteer).
Running the install command by hand showed the reason:
Error: All providers failed for chrome 155.0.8059.79: - DefaultProvider: Extraction failed: no zip archiver is available. Install `unzip` (or `tar.exe`/Powershell on Windows), or add the optional `yauzl` dependency.
Slim Debian images ship without unzip. Fix: apt-get install -y unzip before npm install. Do not trust a green npm install as proof that Chrome is there; check the path with npx puppeteer browsers list in the build.
Stage 1: Code 127, a missing shared library
With unzip added and Chrome downloaded, launch failed with:
Error: Failed to launch the browser process: Code: 127 stderr: /root/.cache/puppeteer/chrome/linux-155.0.8059.79/chrome-linux64/chrome: error while loading shared libraries: libglib-2.0.so.0: cannot open shared object file: No such file or directory
Many people search for this with libnss3.so in the message. Which library appears first depends on the image, because the loader stops at the first one it cannot find. ldd shows the full list:
ldd ~/.cache/puppeteer/chrome/linux-*/chrome-linux64/chrome | grep 'not found'
On the slim image that printed libglib-2.0.so.0, libgobject-2.0.so.0, libnspr4.so, libnss3.so, libnssutil3.so, libsmime3.so, libgio-2.0.so.0, libatk-1.0.so.0, libatk-bridge-2.0.so.0, libdbus-1.so.3, libcups.so.2, libexpat.so.1, libxcb.so.1, libxkbcommon.so.0, libasound.so.2, libgbm.so.1, libX11.so.6, libXext.so.6, libcairo.so.2, libpango-1.0.so.0 and more. Installing them one error at a time takes many rebuilds.
Fix: let Puppeteer install the system packages. It must run as root, on Debian or Ubuntu:
npx puppeteer browsers install chrome --install-deps
Stage 2: Code 1, running as root
With the libraries in place, the next launch failed with a different code:
Error: Failed to launch the browser process: Code: 1 stderr: ERROR:content/browser/zygote_host/zygote_host_impl_linux.cc:103] Running as root without --no-sandbox is not supported. See https://crbug.com/638180.
Docker containers run as root unless the image says otherwise. Chrome refuses to start its sandbox as root. Passing --no-sandbox made the launch succeed (OK Chrome/155.0.8059.79), and that is the line most answers stop at. Read the Chromium sandbox entry before you ship it: without the sandbox, the container is the only barrier between a hostile page and your process.
Stage 3: "No usable sandbox!" as a non-root user
The safer move is a non-root user. As the image's node user, with the sandbox on, Chrome crashed with signal 6:
Error: Failed to launch the browser process: Code: null stderr: FATAL:content/browser/zygote_host/zygote_host_impl_linux.cc:130] No usable sandbox! If you are running on Ubuntu 23.10+ or another Linux distro that has disabled unprivileged user namespaces with AppArmor, see ...
Chrome's sandbox needs user namespaces, and Docker's default seccomp profile blocks the calls it uses. We re-ran the same container with --security-opt seccomp=unconfined and the non-root launch worked with the sandbox on. In production, use a seccomp profile that allows only what Chrome needs instead of turning seccomp off. On an Ubuntu 23.10+ host outside Docker, the same message comes from AppArmor's user-namespace rules, and the fix is an AppArmor profile for the Chrome binary.
A Dockerfile that passes all four stages
FROM node:22-bookworm-slim RUN apt-get update \ && apt-get install -y --no-install-recommends unzip ca-certificates \ && rm -rf /var/lib/apt/lists/* WORKDIR /app COPY package*.json ./ RUN npm ci \ && npx puppeteer browsers install chrome --install-deps \ && mkdir -p /home/node/.cache \ && cp -r /root/.cache/puppeteer /home/node/.cache/ \ && chown -R node:node /home/node/.cache /app COPY . . USER node CMD ["node", "shot.mjs"]
Run it with a seccomp profile that permits the sandbox. We tested the steps of this file inside a running container, not this exact file as a build.
Version matrix
| Environment | puppeteer 22.15.0 | puppeteer 24.10.0 | puppeteer 25.14.0 |
|---|---|---|---|
| Chrome version downloaded | 127.0.6533.88 | 137.0.7151.55 | 155.0.8059.79 |
npm i on slim image without unzip |
Chrome extracted | Chrome extracted | exit 0, no Chrome |
| Missing libraries | not re-tested | not re-tested | Code 127 |
| Root, sandbox on (libraries installed) | not re-tested | not re-tested | Code 1, Running as root |
| Non-root, default seccomp | not re-tested | not re-tested | No usable sandbox! |
| Non-root, seccomp unconfined | not re-tested | not re-tested | OK |
We ran the install row on all three versions and the launch rows on 25.14.0 only.
Symptom, cause, fix
stderr shows |
Cause | Fix |
|---|---|---|
Could not find Chrome (ver. ...) |
Download or extraction failed | Install unzip; run npx puppeteer browsers install chrome |
Code: 127 + error while loading shared libraries |
System libraries missing | --install-deps, or the full apt list |
Code: 1 + Running as root without --no-sandbox |
Root user, sandbox on | Run as non-root, or --no-sandbox for trusted pages |
No usable sandbox! |
Seccomp or AppArmor blocks user namespaces | Seccomp profile or AppArmor rule; --no-sandbox as last resort |
Missing X server or $DISPLAY |
headless: false on a server |
Keep headless, or run under Xvfb |
cache path is incorrectly configured |
Chrome installed as one user, run as another | Copy the cache or set PUPPETEER_CACHE_DIR |
| Works on amd64, fails on arm64 Linux | No Chrome for Testing build for linux arm64 | Use an amd64 image, or a distro Chromium with executablePath |
We reproduced the first four rows and the cache-path message. The $DISPLAY and arm64 rows come from the Puppeteer troubleshooting docs; we did not reproduce them for this page.
The same capture without a local browser
If Chrome exists on your server only to take screenshots, an API removes this whole page of setup. The RenderScreenshot API runs the browser for you; your container needs Node and an API key. With the Node SDK:
import { writeFile } from 'node:fs/promises'; import { Client, TakeOptions } from 'renderscreenshot'; const client = new Client(process.env.RS_API_KEY); const image = await client.take(TakeOptions.url('https://example.com')); await writeFile('example.png', image);
We did not call the live API for this page. The migration guide from Puppeteer maps goto and screenshot options to API parameters. For Selenium's version of the same crash, see DevToolsActivePort file doesn't exist, and for the failures that come after launch, our headless Chrome production failures write-up. Get a free API key to compare.
Related in this topic
- Puppeteer Screenshots: Tested Recipes for Puppeteer 25 Every Puppeteer screenshot recipe re-run on Puppeteer 25.14 and Chrome 155: viewport, full page, element, clip, waits, formats, auth, blocking and fonts.
- Puppeteer on AWS Lambda with @sparticuz/chromium Run Puppeteer on AWS Lambda with @sparticuz/chromium: version matching, a container-image handler tested in the Lambda emulator, and warm reuse.
- Puppeteer in Docker: A Tested Dockerfile with Fonts A non-root Puppeteer Dockerfile with Chromium, CJK and emoji fonts and dumb-init, plus the sandbox error it hits, measured image sizes and launch times.
- Puppeteer Full Page Screenshot: Limits, Lazy Images, Fixes Puppeteer full page screenshot guide: the 16,384 px limit we measured, captureBeyondViewport, lazy-load scrolling, sticky headers and a tested script.
- Hide Cookie Banners and Chat Widgets in Puppeteer Remove cookie banners, consent iframes, shadow-DOM dialogs and chat widgets from Puppeteer screenshots: a tested module and what each method misses.
- Puppeteer HTML to PDF: page.pdf() Options Tested Generate PDFs with Puppeteer page.pdf(): paper size, margins, header and footer templates, page breaks and print CSS, with measured sizes and timings.