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

First, verify which operation failed. If the stack trace says Error: spawn EPERM, includes syscall: 'spawn', and points into Puppeteer’s BrowserLauncher.launch or @puppeteer/browsers, Chrome never started. A later await browser.close() in your script does not prove that closing the browser caused the exception. Treat this as a process-start, executable, account, or filesystem-permission problem. A true shutdown hang is a different failure class and needs different checks.

The Windows report that prompted this question (Puppeteer 24.37.1, Node 25.2.1) is still marked needs-feedback and has no confirmed root cause or maintainer fix. The reliable approach is therefore a diagnostic sequence rather than a universal flag or permission command.

1. Read the complete stack trace before changing permissions

Keep the first error line, the Node fields, and every Puppeteer frame. These clues separate launch failure from shutdown failure.

Failure class When it appears Typical evidence What to investigate
Launch-time spawn EPERM During puppeteer.launch(), before normal page work syscall: 'spawn'; frames under BrowserLauncher.launch or @puppeteer/browsers/.../launch.js Executable path, browser installation, Windows account permissions, writable directories, security software, and supported runtime
Shutdown hang or lingering process After Chrome launched and cleanup begins The program reaches browser.close(), but Chrome remains or the promise never resolves Open pages, GPU flags, container PID 1 behavior, and process reaping

Do not label a launch exception a “browser.close EPERM” error merely because the sample calls browser.close() later. Save the exact stack trace when asking for help; removing the earlier frames often hides the decisive clue.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Sale
LAPGEAR Home Office Pro Lap Desk - Black Carbon, Fits 15.6” Laptops
  • Spacious Design: Measuring 21.1" wide and 14.1" deep, our lap desk comfortably fits most laptops up to 15.6". Extra room for accessories ensures convenience.
  • Enhanced Functionality: Packed with handy features, including a 5x9" precision tracking mouse pad and a built-in phone slot for seamless work or video calls. Plus, enjoy ergonomic support with the integrated cushioned wrist rest.
  • Cool Comfort: Enjoy a stable surface with our lap desk's dual bolster cushion, designed for comfort and airflow, keeping your lap cool during extended use.
  • Durable Surface: Work with confidence on our lap desk's solid surface, featuring a sleek black carbon color, ensuring optimal air circulation to prevent your laptop from overheating.
  • On-the-Go Convenience: With an integrated handle and lightweight design (2.8 lbs), our lap desk is portable for travel or moving around the house, offering flexibility in any space.

2. Reproduce the launch failure with minimal code

Remove application code, extensions, page scripts, and cleanup abstractions. This confirms whether the process can start at all.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: true
  });
  console.log('Chrome launched');
  await browser.close();
})();

If this fails with spawn EPERM, changing page logic or adding more try/finally code cannot fix the initial process creation. If it succeeds, reintroduce your options one at a time until the failing executable, argument, profile, or environment is identified.

3. Windows: verify the browser and installation context

Check the installed versions

Print the Puppeteer version, Node version, and the browser you intend to run. The current Puppeteer system-requirements page lists Node 22.12 or newer and says Puppeteer follows the latest maintenance LTS line. The reported issue used Node 25.2.1; that fact alone does not establish that Node 25 caused the failure or that downgrading will cure it. Use a supported maintenance-LTS runtime for your installed Puppeteer release, then retest.

Determine who supplied Chrome

The full puppeteer package downloads Chrome for Testing and, since Puppeteer 19.0.0, stores managed browsers under ~/.cache/puppeteer by default. puppeteer-core downloads no browser: you must manage one and provide executablePath or a channel. A browser installed by a different account, copied from another machine, or located in a protected directory can therefore produce a different ownership and access situation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
const puppeteer = require('puppeteer-core');

(async () => {
  const browser = await puppeteer.launch({
    executablePath: 'C:\Path\To\chrome.exe',
    headless: true
  });
  await browser.close();
})();

Confirm that the account running Node can read and execute the browser binary and its parent directories. Also check that endpoint-security software has not quarantined, blocked, or isolated the downloaded Chrome executable. Do not disable security controls as a first-line fix; use your organization’s approved allow-list procedure and record the exact executable path.

Understand Puppeteer’s Windows sandbox guidance

Starting with Puppeteer 22.14.0, installation attempts to configure permissions for downloaded Chrome by using Chrome’s setup.exe. If Chrome reports the documented sandbox access-denied error, follow Puppeteer’s Windows permission instructions for the Chrome cache directory. The documentation provides an icacls command for that specific condition and advises a more restrictive SID in high-security environments.

Do not blindly grant broad rights, and do not present that command as a confirmed fix for the newer spawn EPERM report. That report contains no maintainer diagnosis connecting its failure to the sandbox directory. Apply the command only after matching the documented sandbox error and identifying the actual cache path.

4. Containers and read-only filesystems

Chrome writes profile, configuration, cache, and Crashpad data during startup. A read-only image or a mounted directory owned by another user can make launch fail even when the executable itself is readable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
Sale
Yilador Webcam Cover 3 Pack, 0.03 inch Ultra Thin Laptop Camera Cover Slide
  • Note: Not suitable for MacBooks released after 2023 or devices with a protruding front camera; Not applicable to full-screen or notch-style tempered glass screen protectors; Do not use on the rear camera of the phone.
  • 💻 Why Do You Need a Webcam Cover Slide? — Safeguard your privacy by covering your webcam with our reliable webcam cover when not in use. Don't let anyone secretly watch you. Stay protected!
  • ✅ Thin & Stylish — Enhance your laptop's functionality and aesthetics with our 0.027" ultra-thin webcam covers. Seamlessly close your laptop while adding a touch of sophistication.
  • ✅ Fits Most Devices — Compatible with laptops, phones, tablets, desktops! Keep your privacy intact on Ap/ple, Mac/Book, iPh/one, iP/ad, H/P, L/novo, De/ll, Ac/er, As/us, Sa/msung devices.
  • ✅ 365 Days Protection — Our upgraded 3.0 adhesive ensures a strong hold that won't damage your equipment. Experience reliable, long-term privacy protection day in and day out.

Provide writable locations

Give Chrome writable XDG directories and Puppeteer an explicit writable profile directory. Use a mounted volume when the profile must persist between runs.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: true,
    userDataDir: '/tmp/puppeteer-profile'
  });
  await browser.close();
})();
# Example container environment
export XDG_CONFIG_HOME=/tmp/chrome-config
export XDG_CACHE_HOME=/tmp/chrome-cache
mkdir -p "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" /tmp/puppeteer-profile

In production, replace temporary paths with writable volumes and ensure the account that launches Chrome owns them. If the process runs as a non-root user, that user must be able to traverse the browser directory, read the Puppeteer cache, create the profile, and write application and Crashpad files. Puppeteer’s Docker example uses a dedicated non-root user and assigns ownership of its home and application paths; mirror that ownership model rather than running Chrome as root.

Separate filesystem errors from process-reaping problems

A profile or Crashpad access message points toward writable paths. A Chrome process that remains after a successful launch points toward cleanup and process reaping. In Docker, PID 1 has special signal and child-process behavior; Puppeteer’s troubleshooting guidance notes that an init such as dumb-init may help reap zombie Chrome processes. That advice does not explain a Windows launch-time spawn EPERM.

5. Keep Chrome’s sandbox enabled

Puppeteer’s documentation states: “Running without a sandbox is strongly discouraged. Consider configuring a sandbox instead.” The sandbox protects the host from untrusted web content. Do not add --no-sandbox as a generic EPERM remedy.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
AboveTEK Portable Laptop Lap Desk w/Retractable Left/Right Mouse Pad Tray, Non-Slip Heat Shield Tablet Notebook Computer Stand Table w/Sturdy Stable Work Surface for Bed Sofa Couch or Travel
  • Anti-Slip Surface - Transform your laptop into a mobile workstation with the AboveTEK portable laptop lap desk. The anti-slip surface provides a strong grip for laptops up to 15.6 inches(Diagonal), while the double rubber strip on the bottom ensures a stable display or typing experience on your lap, couch, or bed.
  • Retractable Mouse Pad - Retractable laptop mouse pad extends on both directions for the left/right handed with elevation along the edges for stopping mouse from falling off. The size of laptop tray is 14" X 9.7" and the size of mouse pad is 7.4" X 6.1".
  • Effective Heat Shield - The effective heat shield made of sturdy and thick material protects your laptop from overheating. Prioritizes your comfort and safety, an ideal lap pad or board for working anywhere.
  • EASY to Carry and Store - With an ergonomic and simplistic design, the lap desk is portable to store in a backpack. Only 15" in size, 2.2 lb of weight and with slim 0.6 inch thickness, it is ready to be easily carried around.
  • Widely Applicable - The smooth platform accommodates laptops and tablets up to 15.6 inches(Diagonal), making it a versatile accessory and one of the best gifts for mom, dad, students and professionals. Perfect for use as a laptop bed tray or tablet holder anywhere at home, library, or park.

Only in an environment where the content is absolutely trusted, and after you understand the security trade-off, might a temporary diagnostic run without the sandbox distinguish a sandbox-specific failure from another launch problem. If that changes the result, fix the sandbox configuration and permissions; do not ship the insecure flag as the permanent solution.

6. If Chrome launched, diagnose shutdown separately

When the browser starts but browser.close() hangs, log the point at which each operation completes and inspect open pages:

const pages = await browser.pages();
console.log('pages before close:', pages.length);
for (const page of pages) {
  await page.close();
}
await browser.close();

A historical Windows report against Puppeteer 13.1.1 described Chromium not closing with the combined flags --in-process-gpu and --use-gl=swiftshader. Its reporter’s workaround was to “close all pages before call to browser.close().” This is a narrow, unconfirmed report, not a general fix for current Puppeteer or for launch-time EPERM. Remove those flags or test them independently before relying on the workaround.

7. A repeatable diagnostic checklist

  1. Capture the complete stack trace and classify the failing operation as launch or shutdown.
  2. Run the minimal script with no custom flags, pages, extensions, or application code.
  3. Record Node and Puppeteer versions; use a supported maintenance-LTS Node release for the Puppeteer version installed.
  4. Identify whether puppeteer downloaded Chrome or whether puppeteer-core is using a separately managed executable.
  5. Verify the launching account can execute Chrome and read the Puppeteer browser cache.
  6. On Windows, match any sandbox access-denied message to Puppeteer’s documented permission procedure before using icacls.
  7. In containers, make XDG config/cache directories and userDataDir writable and verify ownership.
  8. Keep the sandbox enabled; treat --no-sandbox only as a tightly controlled diagnostic for trusted content.
  9. For a post-launch hang, close pages, remove unusual GPU flags, and investigate PID 1 and zombie reaping in containers.
  10. Reintroduce custom options one at a time and retain the first configuration that reproduces the error.

8. Common symptoms, causes, and fixes

Symptom Likely area Next action
spawn EPERM with syscall: 'spawn' Child-process creation Check executable path, account access, security controls, browser installation, and the full launch stack.
Sandbox access denied Chrome sandbox permissions Use Puppeteer’s documented Windows cache-directory procedure; do not generalize it to every EPERM.
Profile, Preferences, or Crashpad database access denied Read-only or incorrectly owned directory Set writable XDG paths and userDataDir; fix volume ownership for the runtime user.
Executable not found with puppeteer-core No browser is downloaded automatically Install/manage Chrome yourself and provide a valid executablePath or channel.
Chrome remains after successful work Shutdown or process reaping Close pages, test without the historical GPU-flag combination, and use an init process in containers where appropriate.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

9. Or skip the browser setup

If your goal is a reliable website image rather than controlling a local Chrome process, ScreenshotNeo provides a hosted screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF output without requiring local Puppeteer installation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
Sale
LAPGEAR Home Office Lap Desk – Pink, Fits 15.6” Laptops
  • Spacious Design: Measuring 21.1" wide and 12" deep, our lap desk comfortably fits most laptops up to 15.6". Extra room for accessories ensures convenience.
  • Enhanced Functionality: Packed with handy features, including a 5x9" precision tracking mouse pad and a built-in phone slot for seamless work or video calls. Plus, enjoy laptop support with the integrated device ledge.
  • Cool Comfort: Enjoy a stable surface with our lap desk's dual bolster cushion, designed for comfort and airflow, keeping your lap cool during extended use.
  • Durable Surface: Work with confidence on our lap desk's solid surface, featuring a blush pink color, ensuring optimal air circulation to prevent your laptop from overheating.
  • On-the-Go Convenience: With an integrated handle and lightweight design (2.14 lbs), our lap desk is portable for travel or moving around the house, offering flexibility in any space.

Example using cURL (see the ScreenshotNeo documentation for all options):

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

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Before capture, ScreenshotNeo accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

10. When a remote browser is the better architecture

If policy prevents local Chrome from starting, puppeteer-core can connect to a browser managed elsewhere. Puppeteer documents this for remote browsers and for teams that manage browser binaries themselves. A remote design changes where permissions, sandboxing, profiles, and process supervision are handled; it does not prove or repair the unresolved Windows issue. Validate authentication, network reachability, browser version compatibility, and data-handling requirements before adopting it.

Frequently Asked Questions

Does browser.close() cause every Puppeteer EPERM error?

No. A stack trace containing spawn EPERM and syscall: 'spawn' identifies child-process creation during launch, even if the script later calls browser.close().

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

Should I always add --no-sandbox on Windows or Docker?

No. Puppeteer strongly discourages running without a sandbox. Fix sandbox, account, and writable-path configuration instead; use the flag only as a controlled diagnostic with absolutely trusted content.

Why does puppeteer-core behave differently from puppeteer?

puppeteer downloads and manages Chrome for Testing, while puppeteer-core downloads no browser and requires your own executable or channel configuration.

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.