Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Browser closed unexpectedly means Chromium exited while Pyppeteer was trying to start it—before your page code, selectors, or navigation ran. Start by launching with dumpio=True and reading Chromium’s stderr. Then check, in order, that the browser exists in the final image, can run as the application’s user, has its required Linux libraries, and has a viable sandbox and Docker process/IPC setup.

The right fix depends on the stderr message. Adding --no-sandbox to every container may hide a sandbox problem, but it also disables a security boundary. Prefer a non-root browser with a working sandbox; use no-sandbox flags only when your environment cannot provide one and you accept the trade-off.

What the error means—and what it does not

Pyppeteer starts a Chromium process and waits for Chromium to return its DevTools WebSocket endpoint. If Chromium exits before that happens, the launcher raises BrowserError('Browser closed unexpectedly:n...'). This is a browser startup failure: page creation, selectors, JavaScript, and page navigation have not yet had a chance to run.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The message alone does not identify the cause. Chromium may have rejected the sandbox configuration, failed to load a shared library, been launched from a nonexistent or incompatible executable, lacked permission to run, or crashed under resource pressure. Get the browser’s own output before changing several settings at once.

Step 1: expose Chromium’s stderr

Set dumpio=True in the Pyppeteer launch options. This sends the browser process’s stdout and stderr to the application output, where Docker logs can show the more useful underlying message. Keep the initial test small: launch one browser, create one page, and navigate to one URL.

import asyncio
from pyppeteer import launch

async def main():
    browser = None
    try:
        browser = await launch({
            "headless": True,
            "dumpio": True,
            # Set only if this executable is installed in the image:
            # "executablePath": "/usr/bin/chromium",
            "args": ["--no-sandbox", "--disable-setuid-sandbox"],
        })
        page = await browser.newPage()
        await page.goto("https://example.com", {"waitUntil": "networkidle2"})
    finally:
        if browser:
            await browser.close()

asyncio.get_event_loop().run_until_complete(main())

This is a diagnostic pattern, not a recommendation to disable sandboxing unconditionally. If the container supports a working sandbox, remove both no-sandbox flags and run with the appropriate non-root user and container configuration. The executable path and system packages vary by image; there is no universally correct Chromium path or dependency list.

Read the first specific error, not just the final exception

  • Sandbox or permissions: look for wording such as “No usable sandbox” or permission failures.
  • Executable or revision: check whether the browser path is missing, inaccessible, or incompatible with the Pyppeteer bundle.
  • Shared-library loader: look for a missing library or loader error; the generic Pyppeteer exception cannot name the package to install.
  • Crash under load: compare a single-page launch with the failing workload and inspect shared-memory, memory, and process limits.

Step 2: make the browser available inside the final image

Pyppeteer normally downloads its bundled Chromium on first use. Its project documentation describes that download as approximately 100 MB. In a container build, relying on a first-run download can leave the browser absent at runtime—for example, if the build and runtime use different users or cache locations, or if the final image does not contain the downloaded files.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Run pyppeteer-install while building the image, then verify that the resulting executable is present in the final image and accessible to the user that starts the application. If you set a cache location, make sure the runtime uses the same location. A successful download in an earlier build stage is not proof that the executable made it into the deployed image.

The Pyppeteer project says it works best with its bundled Chromium and does not guarantee compatibility with arbitrary Chrome versions. Prefer the bundled revision when possible. If you choose a distribution-installed browser instead, pass its absolute in-container path through executablePath and test that exact binary as the application user.

Check from the container, not from the host

  • Confirm the executable exists at the path configured in executablePath inside the running or final image.
  • Confirm the process user can execute it and read the files it needs.
  • Do not copy a host path such as /usr/bin/chromium into configuration unless the same path exists in the image.
  • If Chromium reports a missing shared library, install the dependency required by the particular browser package, then verify again in the image. The correct package name is image-specific.

Step 3: choose a sandbox policy deliberately

A container’s sandbox configuration is a security decision as well as a launch setting. The preferred approach is to run Chromium as a non-root user with a functional sandbox and the container capability and seccomp setup required by the image. The Puppeteer Docker guidance for its sandboxed image specifies the SYS_ADMIN capability; do not assume that requirement or its full setup is identical for every base image.

If the environment cannot provide a usable sandbox, --no-sandbox is a documented fallback in Puppeteer troubleshooting guidance. A Pyppeteer issue discussion also shows --disable-setuid-sandbox used with it as a workaround. Disabling sandboxing reduces browser isolation, so do not treat these switches as harmless boilerplate, especially when rendering pages from untrusted sources.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the configuration that matches the container

Approach When it fits Trade-off
Non-root user with working sandbox The image and runtime can provide the browser’s required sandbox and security configuration. Requires correct user, capability, and seccomp setup for that image.
No-sandbox fallback The environment cannot provide a usable sandbox and the risk is accepted. Less browser isolation; only use where that security trade-off is appropriate.

Do not add flags merely because they appear in an example online. Use stderr to establish that sandbox policy is actually the failing branch, and align the launch arguments with the container security model.

Step 4: stabilize Docker process and shared-memory behavior

Chromium launches child processes. Starting a container with --init gives PID 1 a small init process to reap children, which helps avoid process-lifecycle problems in containers. If Chromium launches once but crashes under heavier navigation or multiple pages, shared memory may be the issue. The official browser-container guidance recommends trying --ipc=host because Chromium can run out of shared memory without it.

These settings solve different problems: --init addresses child-process reaping, while --ipc=host changes the container’s IPC/shared-memory arrangement. Try the relevant change based on the symptoms rather than adding both as an unexplained bundle. Also reduce page concurrency and inspect container memory and PID limits when failures correlate with load.

For a sandboxed official browser image, follow that image’s documented non-root and seccomp guidance, including its stated SYS_ADMIN capability requirement. Do not copy privileged flags to an unrelated image without checking its security documentation.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Step 5: isolate startup from application behavior

  1. Enable dumpio=True and capture the full container logs.
  2. Run a minimal Pyppeteer launch using the same image, user, and launch arguments as production.
  3. Navigate to one page only after launch and page creation succeed.
  4. Close the browser in a finally block so test failures do not leave the browser lifecycle ambiguous.
  5. Only then restore application concurrency, custom navigation waits, and other workload-specific settings one at a time.

If the minimal launch works but the application still fails, the original startup issue may be resolved while a separate workload problem remains. Reintroduce concurrency and heavier page behavior gradually, watching for crashes and resource-limit symptoms.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting by symptom

“No usable sandbox” or a permission error

Use a non-root browser process and configure the sandbox and container permissions required by the selected image. If that cannot be done, the no-sandbox fallback may permit startup, but it gives up browser isolation; decide whether that is acceptable for the pages being rendered.

The configured browser path is missing or Chromium exits immediately

Check the path from inside the final container. If using Pyppeteer’s bundled browser, install it during the image build and confirm its cache is retained at runtime. If using a distro-installed executable, set executablePath to its absolute in-container path and ensure the app user can execute it.

Loader output names a missing library

This indicates a system dependency problem rather than a selector or navigation bug. Install the dependencies required by the specific Chromium package and base image. Because the needed packages are image-specific, use the loader message and package documentation rather than guessing a generic list.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The browser works for one page but crashes with parallel work

Reduce concurrency and compare behavior under the same resource limits. Try --ipc=host when shared-memory pressure is plausible, and inspect memory and PID limits. Avoid interpreting a successful low-load test as evidence that the production workload has adequate resources.

Best Value
Docker Container Linux Devops Programming Coding T-Shirt
  • Docker, Docker Swarm, Docker Compose, Programmer, Developer, Coding, Programming, Software Engineer, Code, DevOps, Deploy, Deployment, Kubernetes, Salt, Puppet, Chef, Terraform, Container, AWS, Azure, Cloud, Geek, Funny, Computer, Software, Tech, IT
  • Integration, Scrum, Compile, Compilation, Science, Bug, Debug, Python, Linux, Java, Javascript, Scala, Dotnet, Kotlin
  • Lightweight, Classic fit, Double-needle sleeve and bottom hem

Repeated launches leave child processes behind

Start the container with --init or use a proper init entrypoint so PID 1 reaps child processes. Keep explicit browser cleanup in the application’s success and error paths.

Or skip the browser setup

If your goal is to obtain a website screenshot rather than operate Chromium yourself, ScreenshotNeo is a website screenshot API and MCP server. A single request returns an image or PDF without requiring you to package Pyppeteer and Chromium into your Docker image. See the ScreenshotNeo API documentation for options and response details.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo accepts consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and responses identify the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, or other MCP clients. The free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Sign up for 1,000 free screenshots a month with no card.

Frequently Asked Questions

Will setting executablePath fix every “Browser closed unexpectedly” error?

No. It selects the browser binary; it does not supply missing libraries, resolve sandbox permissions, or increase Docker resources. Use Chromium’s stderr to identify which startup condition failed.

Should I install system Chromium or use Pyppeteer’s downloaded browser?

Pyppeteer’s project recommends its bundled Chromium for compatibility and does not guarantee arbitrary Chrome versions. A system browser is an option when you deliberately configure and test its in-image absolute path and compatibility.

Can I diagnose this by changing page selectors or navigation waits?

Not initially. The launcher error occurs before the page code and selectors run. First get a minimal browser launch working; investigate navigation behavior only after startup succeeds.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.