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

The Puppeteer error Execution context was destroyed, most likely because of a navigation usually means your script tried to evaluate JavaScript in a page or frame whose document context had just been replaced or disposed. If a click or form submission is supposed to navigate, start waiting for navigation before triggering it. If the page may update without navigating, wait for the specific state your next step needs instead.

What the error means

Puppeteer evaluates page JavaScript inside an execution context associated with a page or frame. When navigation replaces a document, its old context is destroyed. An evaluation that overlaps that transition can fail because it no longer has a live context to use.

Puppeteer’s current CDP IsolatedWorld implementation tracks context creation and disposal; if the isolated world is disposed before a replacement context becomes available, its wait path constructs an Execution context was destroyed error. That implementation detail explains the failure mode, but the error alone does not establish that Chromium crashed, Puppeteer is defective, or the host environment is at fault. See the Puppeteer IsolatedWorld implementation.

Navigation is a common trigger, but the key diagnostic is timing: identify which operation was using the context when it went away. Clicks, form submissions, redirects, reloads, history changes, and frame detachment can all change which document or frame your code is addressing.

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.

Choose the right wait for the transition

Before changing timeouts or retrying evaluations, decide whether the interaction causes a full document navigation or an in-page state change. The wait must represent the condition that makes the next operation safe.

What the interaction does What to wait for Why
A full navigation is expected page.waitForNavigation(), started before the click or submission Registering the wait first avoids missing a fast navigation.
Navigation is optional, or the app updates in place A result-specific selector or application-state signal A document load may never happen in a single-page app or modal interaction.

Choose a navigation lifecycle condition according to what the next step needs. domcontentloaded is often enough to work with the parsed document; a later event or specific selector may be needed for content rendered afterward. Do not use networkidle reflexively: persistent requests can make it an unsuitable readiness signal.

Fix an expected navigation

Start the navigation wait before triggering the action, then await both together. For example, if clicking a link should navigate:

await Promise.all([
  page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
  page.click('a#navigate-away'),
]);

const title = await page.title();

The same pattern applies to a form submission if it is expected to load another document: replace the click with the submission action your script uses. After the wait resolves, query the new page rather than trying to continue with assumptions about the unloading document.

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

If the workflow needs content that appears after the document is parsed, wait for that content specifically after navigation. A lifecycle event says something about document loading; it does not necessarily prove that a client-rendered result is ready.

Fix an in-page update or uncertain navigation

When a click might update the current page, open a modal, or navigate depending on the result, do not blindly require navigation. Wait for an element that identifies the state your next operation needs:

await page.click('button#submit');
await page.waitForSelector('.success-message');
const message = await page.$eval(
  '.success-message',
  el => el.textContent
);

Use a selector that distinguishes the completed state from the previous page state. A broad selector such as h1 only helps if its appearance or content reliably indicates that this particular workflow has completed. For a single-page application, a result-specific selector or an application-state signal is usually more meaningful than waiting for a document navigation that will not occur.

Handle reloads, redirects, and frame changes

After a reload or redirect

Wait for the relevant navigation or resulting state before querying the page. Then reacquire selectors and element handles from the new document. An element handle belongs to the context in which it was obtained; do not assume it remains usable across a document replacement.

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

A Puppeteer issue reports a selector query failing after page.reload() on one website, while a different website did not reproduce it. The report used Puppeteer 20.7.3, Node 20.3.0, and macOS, so it illustrates site-dependent behavior rather than a current compatibility guarantee. See Puppeteer issue #10435.

When working with frames

Confirm that the operation is aimed at the frame that still exists and contains the target content. If an interaction navigates or detaches a frame, a handle or evaluation associated with its old context may no longer be valid. Wait for the relevant transition, locate the current frame as needed, and reacquire the target there.

Debug intermittent and CI-only failures

Use the failing stack trace and action sequence to find the race rather than assuming the environment is responsible. A CI report mentions differences between local and CI Node.js and Puppeteer versions, alongside navigation, form, wait, missing-element, and timeout issues; it does not isolate a universal CI-specific cause. See Puppeteer issue #12968.

  1. Record the exact Puppeteer call that fails and whether it acts on a page, frame, or element handle.
  2. Check whether the preceding click, form submission, page.reload(), goto(), redirect, or history action navigated or detached a frame.
  3. If navigation is expected, register and await waitForNavigation() before the action, commonly with Promise.all().
  4. If navigation is uncertain, wait for the result-specific selector or application-state signal instead.
  5. Reacquire selectors and handles after the transition; do not carry handles from the old document forward.
  6. If it still fails, compare the exact runtime and Puppeteer versions in the lockfile and CI image, and log the URL before and after the action, active frame, wait condition, and timeout.

Common causes and fixes

Symptom or pattern Likely explanation Fix
Error immediately after clicking a link The click navigated while a query or evaluation was still targeting the old document. Start waitForNavigation() before the click and query after it resolves.
Error after submitting a form The submit caused a navigation, or the result state was not ready when queried. Wait for navigation if a new document is expected; otherwise wait for a result-specific selector.
Error after page.reload() The old document context or its handles were replaced; behavior can depend on the site. Wait for the reload transition, then reacquire elements.
Navigation wait times out The interaction may update the page in place, or the chosen lifecycle event may not match the workflow. Confirm whether a document navigation occurs; use a state-specific wait when it does not.
Failure appears only in CI Runtime, Puppeteer, timing, or workflow differences may be involved; a CI-only report does not by itself identify one cause. Compare exact versions and action timing, and collect URL, frame, and wait-condition details in both environments.
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 website screenshot rather than browser automation, ScreenshotNeo provides a screenshot API and MCP server. Its one-call request can return an image or PDF, without you setting up a Puppeteer navigation wait:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
The SQL Programming Language: .
  • Used Book in Good Condition
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are not billed. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

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

Frequently Asked Questions

Does this error mean Chromium crashed?

No. It means the operation encountered a destroyed execution context; use the stack trace and surrounding actions to determine why.

Should I always wait for navigation after a click?

No. Wait for navigation only when the interaction is expected to load a new document; for in-page updates, wait for the resulting state.

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

Can I reuse an element handle after a reload?

Do not rely on it. Reacquire the element after the new document or frame state is ready.

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.