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

The error means Puppeteer lost its connection to Chromium while waiting for navigation; it does not identify the root cause. Chromium may have crashed or exited, your code may have called browser.close() or browser.disconnect(), or the protocol transport may have failed. Capture browser and Node logs first, then isolate lifecycle, version, navigation, resource, and deployment variables one at a time.

What the error actually means

Puppeteer emits a disconnected event when its connection to the browser ends. The documented possibilities include the browser closing, the browser crashing, or application code explicitly calling browser.disconnect(). The navigation message is therefore a symptom observed during page.goto() or another wait, not a diagnosis of why Chromium disappeared. See the browser-management guide and BrowserEvent reference.

Do not begin by copying a collection of launch flags from an issue comment. First establish exactly which operation failed and whether the browser process was still alive.

1. Record a reproducible baseline

Make a short script that launches one browser, creates one page, performs one operation, and closes cleanly. Record these details for both a working and failing run:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Puppeteer package version and the browser executable path and version.
  • Node.js version, operating system, container image or serverless runtime.
  • The exact operation: page.goto(), page.setContent(), PDF generation, or another call.
  • The complete waitUntil value, timeout, URL or HTML shape, and whether external resources are loaded.
  • Every launch argument, environment variable, proxy, custom executable, and remote-connection setting.
  • Whether the failure is deterministic, intermittent, CI-only, or associated with concurrency.

Version-specific GitHub reports cannot establish a universal cause. Comparing a minimal local run with the deployment is more useful than assuming that a particular Chromium flag, memory size, or Puppeteer release is responsible.

2. Watch the browser lifecycle

Attach the event listener immediately after launch and log every cleanup path. Also distinguish the two lifecycle methods: browser.close() closes the browser, while browser.disconnect() detaches Puppeteer and leaves the browser process running.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: true,
    dumpio: true
  });
  browser.on('disconnected', () => {
    console.error('Puppeteer disconnected at', new Date().toISOString());
  });

  try {
    const page = await browser.newPage();
    page.on('error', err => console.error('Page error:', err));
    page.on('pageerror', err => console.error('Page JavaScript error:', err));
    await page.goto('https://example.com', {
      waitUntil: 'domcontentloaded',
      timeout: 30000
    });
    console.log('navigation completed');
  } finally {
    await browser.close();
  }
})().catch(err => {
  console.error(err);
  process.exitCode = 1;
});

Search all code paths—including timeout handlers, test teardown, queue workers, and invocation-finally blocks—for browser.close(), browser.disconnect(), or process termination. A cleanup timer that fires while navigation is pending can produce the same message as a crash.

3. Capture Chromium and protocol evidence

Run the smallest reproduction with dumpio: true. Puppeteer’s debugging guide recommends forwarding browser stdout and stderr when Chromium fails to launch or crashes. Preserve those streams together with timestamps from launch, page creation, navigation start, navigation completion, and cleanup.

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

If the basic output is insufficient, use the protocol-logging and pending-call inspection techniques documented in that guide. Treat verbose protocol output as sensitive: it can contain page URLs, headers, cookies, form data, or other credentials. Redact secrets before sharing logs.

Interpret the evidence

  • Chromium exits before the error: investigate the browser crash, executable, host limits, sandbox configuration, or an incompatible launch setup.
  • Your cleanup code runs first: fix the lifetime or timeout logic; changing navigation readiness cannot reconnect a closed browser.
  • The transport drops with no browser exit evidence: investigate the remote endpoint, container termination, process supervisor, or network path.
  • The browser remains alive and only a readiness wait fails: separate the readiness condition from the operation that needs the page.

4. Separate navigation readiness from browser survival

waitUntil controls when Puppeteer considers navigation ready. It does not keep Chromium alive. The network-idle documentation describes waiting for network quiet for at least the configured idle interval. Analytics, advertisements, long-polling, WebSockets, service workers, or an external resource can prevent that condition from being reached.

To isolate this variable, test a less restrictive condition, then wait for the specific thing your job requires:

await page.goto(targetUrl, {
  waitUntil: 'domcontentloaded',
  timeout: 30000
});
await page.waitForSelector('#report-ready', { timeout: 15000 });

Use load when the page’s load event is meaningful, or networkidle0/networkidle2 only when network quiescence is genuinely required. A historical report about external SSL resources during setContent found that domcontentloaded worked where networkidle0 did not; that is a version- and page-specific observation, not a guaranteed fix.

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

Do not wait for an event your operation will not emit

page.setContent() replaces document content; it is not a URL navigation. Do not create an unrelated page.waitForNavigation() promise around it. Instead, set the content and wait for a selector, a known response, or an explicit application signal:

await page.setContent(html, { waitUntil: 'domcontentloaded' });
await page.waitForSelector('#rendered', { timeout: 15000 });

This removes a misleading wait from the diagnostic, but it does not by itself prove why a browser disconnected.

5. Check deployment, load, and browser compatibility

Local versus CI, containers, and serverless

Run the identical minimal script locally and in the failing environment. Compare browser stderr, runtime logs, executable paths, timeout behavior, process exit codes, and resource-limit observations. Check whether the invocation ends while work is pending, whether a supervisor kills Chromium, and whether several jobs share one browser instance.

Reports describe failures in Lambda PDF generation, custom launch configurations, and high-concurrency workloads, but they do not establish a universal concurrency threshold or a canonical memory setting. Do not blindly add --single-process, disable the sandbox, alter SSL handling, or increase memory. Make one evidence-based change, rerun the minimal script, and retain the before-and-after logs.

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

Verify the package and browser pair

Record the installed Puppeteer version, Node version, executable path, and actual browser version. Confirm that the deployment uses the browser intended by that Puppeteer release rather than an unrelated system binary. The issue reports below are historical snapshots—not compatibility guarantees:

Report Context How to use it
Issue #11632 (opened January 4, 2024) Lambda PDF generation; example used Puppeteer 21.6.0 and older Chromium-related packages; closed as not planned. Compare versions and invocation lifetime; it is not a confirmed universal cause.
Issue #10491 (opened July 1, 2023) page.goto() with custom launch options including --single-process. Test custom flags one at a time; the report does not prove that flag caused the failure.
Issue #5002 (opened October 3, 2019) setContent, external SSL resources, and networkidle0; reporter said domcontentloaded worked. Use as a readiness/resource hypothesis only; it is historical.
Issue #3927 (opened February 6, 2019) High-concurrency Lambda workload with Puppeteer 1.11.0. Compare concurrency and process lifetime; it supplies no general threshold.

6. Change one variable at a time

  1. Save the baseline script, versions, logs, and exact failure timing.
  2. Change only the launch configuration or executable, then rerun.
  3. Restore it and test external-resource loading or the waitUntil value.
  4. Restore that change and test concurrency, timeout, and cleanup timing.
  5. For setContent, remove unrelated waitForNavigation calls and wait for a concrete selector.
  6. Record the result and retain the smallest script that still fails.

This method distinguishes browser termination from a page that simply never reaches the chosen readiness condition.

Common symptoms and targeted fixes

  • Disconnect occurs immediately after a timeout: inspect timeout handlers and finally blocks for premature close/disconnect calls.
  • Only networkidle0 fails: inspect persistent requests and test a suitable readiness condition plus an explicit selector or response wait.
  • Only external HTML assets trigger it: capture browser stderr and resource failures; test with external assets removed to isolate the page from the browser lifecycle.
  • Only CI or Lambda fails: compare executable paths, process lifetime, concurrency, host limits, and invocation logs with a local run.
  • Only a custom Chromium build fails: verify the browser version and launch arguments against the installed Puppeteer package.
  • Logs contain credentials: redact protocol output, URLs, cookies, authorization headers, and page data before distributing it.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is a reliable image or PDF rather than diagnosing a Puppeteer runtime, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the result with X-Page-Verdict and X-Billed headers. Its MCP server supplies take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

One GET request returns PNG, JPEG, WebP, or PDF:

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}`);

See the ScreenshotNeo documentation for options such as full-page capture with lazy-image loading, CSS-selector element capture, device presets, custom viewport and retina scale, PDF paper and page ranges, custom CSS or JavaScript, clicks, selector waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage data, and OpenAPI compatibility. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

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

FAQ

Does changing waitUntil fix a disconnected browser?

It can isolate a page-readiness problem, but it cannot reconnect a browser that crashed, exited, or was intentionally disconnected.

Best Value
The SQL Programming Language: .
  • Used Book in Good Condition

Should I always add --no-sandbox or --single-process?

No. Those are environment-specific changes. Add them only when logs and deployment constraints support the change, and test one variable at a time.

Is the message proof of an out-of-memory crash?

No. Memory pressure is one hypothesis among browser crashes, cleanup races, transport loss, incompatible binaries, and deployment termination. Browser stderr and process/runtime logs are needed to distinguish them.

Frequently Asked Questions

Can a remote browser cause the same Puppeteer message?

Yes. A dropped protocol transport or terminated remote endpoint also ends Puppeteer’s browser connection, so inspect both endpoint and client logs.

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

What should I include in a bug report?

Provide a minimal reproduction, Puppeteer and browser versions, Node/runtime and operating system, launch arguments, exact operation and wait condition, timestamps, and redacted browser/Node logs.

The Bottom Line

Find out why Chromium disconnected before changing flags: log the lifecycle, capture browser stderr, verify versions and deployment limits, and separate readiness waits from browser survival. Then change one variable and verify the result.

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.