What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
“Execution context was destroyed, most likely because of a navigation” means Puppeteer is trying to run JavaScript in a document that Chrome has already replaced. The usual fix is to start the appropriate wait before the click or form submission, then reacquire selectors and element handles after the new document is ready. If no navigation occurs, waiting for navigation is the wrong fix: wait for the selector, request, or response that your next step actually needs.
What the error means
An execution context is the JavaScript environment associated with a particular page document (and, in some cases, a frame). Puppeteer creates and disposes these contexts as Chrome reports that execution contexts were destroyed or all contexts were cleared. When a click, submit, redirect, reload, or script replaces the document, handles and evaluations tied to the old context can no longer be used.
For example, this sequence is vulnerable:
await page.click('a.checkout');
await page.evaluate(() => document.title);
If the click starts navigation, the evaluation can race with destruction of the old document. The same race can happen with an element handle, a form submission, a redirect chain, or a reload. Issue reports show these patterns in particular sites and Puppeteer/Node versions; they are examples rather than proof that every occurrence has one identical cause.
First determine what actually happens after the action
Full document navigation
A new URL or document loads after the action. This includes ordinary links, form posts, redirects and explicit reloads. Pair the action with page.waitForNavigation().
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
Single-page application state change
The URL may stay the same while the application renders a success panel or replaces a component. A navigation wait can time out here. Wait for the resulting selector instead.
Network-driven completion
The meaningful event may be one API request or response. Use page.waitForRequest() when you need to know that a request was sent, or page.waitForResponse() when the server result matters.
Frame navigation
If the action occurs inside an iframe, make sure you are operating on the correct frame and wait for that frame’s resulting state. A page-level selector or handle from another document is not interchangeable with one in the frame.
Fix an expected navigation with Promise.all
Register the navigation wait before triggering the action. Starting the wait after an awaited click can miss a fast navigation.
const [response] = await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.click('a.checkout'),
]);
// This query runs in the new document.
await page.waitForSelector('.checkout-page');
const heading = await page.$eval('.checkout-page h1', el => el.textContent.trim());
console.log({ url: page.url(), status: response && response.status(), heading });
domcontentloaded means the initial document has been parsed; it does not guarantee that a client-rendered widget or API result is ready. Add a selector wait for the state your next operation requires. Other useful waitUntil values are load, networkidle0, and networkidle2, but network-idle conditions can be a poor fit for pages with analytics, polling, or persistent connections.
Form submission
await page.type('#email', '[email protected]');
const [response] = await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.click('button[type="submit"]'),
]);
await page.waitForSelector('.account-home');
Redirect chains
A single click can pass through several URLs. The navigation promise represents completion of the navigation sequence, but your final readiness check should target the destination page, not an intermediate URL.
When navigation is uncertain, wait for the outcome you need
Wait for a rendered element
await page.click('button.submit');
await page.waitForSelector('.success-message', { visible: true });
const message = await page.$eval('.success-message', el => el.textContent.trim());
This is appropriate when the application updates the current document without a full navigation. Selectors should describe the state needed by the next step, such as a visible success message rather than a generic container that exists before submission.
Wait for a specific response
const responsePromise = page.waitForResponse(response =>
response.url().endsWith('/api/orders') &&
response.request().method() === 'POST' &&
response.status() === 201
);
await page.click('button.submit');
const response = await responsePromise;
console.log(await response.json());
Create the response wait before the action, just as with navigation. Match URL, method and status tightly enough to avoid resolving on unrelated traffic.
Wait for a request
const requestPromise = page.waitForRequest(request =>
request.url().endsWith('/api/orders') && request.method() === 'POST'
);
await page.click('button.submit');
const request = await requestPromise;
console.log(request.postData());
A request wait proves that the browser sent the request; it does not prove that the server accepted it. Use a response wait when acceptance or returned data is the condition that matters.
Never reuse handles from the old document
An ElementHandle belongs to the execution context in which it was obtained. After navigation, reacquire it.
Rank #3
const oldButton = await page.$('#continue');
const [nav] = await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
oldButton.click(),
]);
// Do not call oldButton again. Query the destination document.
const newButton = await page.$('#next-step');
if (!newButton) throw new Error('Destination did not render #next-step');
await newButton.click();
The same rule applies to values captured by page.evaluate(). Perform the evaluation again after the new document is ready.
A practical diagnostic workflow
- Log the action and URL. Record
page.url()immediately before and after the trigger. - Classify the transition. Decide whether it is a document navigation, redirect, reload, SPA render, request, or response.
- Attach the wait first. Put the wait and trigger in one
Promise.allwhenever both must start together. - Use the narrowest readiness signal. Choose a destination selector, exact response predicate, or navigation lifecycle stage.
- Reacquire everything. Query selectors and handles only after the new state is ready.
- Check frames. Confirm that the selector is in the page or frame where you are searching.
- Inspect the real failure. A timeout can mean the event never occurred, the predicate was too broad or narrow, or the action did not run—not merely that the timeout was too short.
Common traps and fixes
Starting navigation waiting after the click
Symptom: navigation wait times out or the following evaluation reports a destroyed context. Fix: create page.waitForNavigation() before page.click(), normally in Promise.all.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Adding a navigation wait to a non-navigating action
Symptom: a timeout even though the UI visibly succeeded. Fix: remove the navigation wait and wait for the success selector or matching API response.
Using a broad response predicate
Symptom: the script continues before the intended data arrives. Fix: match the endpoint, HTTP method and relevant status (and, where useful, request payload).
Keeping a stale element handle
Symptom: a later click or evaluation fails after a redirect or reload. Fix: reacquire the element from the destination document.
Rank #4
Assuming domcontentloaded means the app is ready
Symptom: the page has loaded but a component is missing. Fix: add a selector or response wait for that component’s actual readiness.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Only increasing timeouts
Symptom: a longer timeout changes nothing. Fix: verify that the expected event occurs and that the URL, selector, frame and predicate describe the real result. A timeout cannot make a never-fired event occur.
Choosing the right wait
| What the next operation depends on | Use | Important detail |
|---|---|---|
| A new document or URL | page.waitForNavigation() |
Register before the action; select an appropriate lifecycle stage. |
| A particular element or UI state | page.waitForSelector() |
Match visibility and state needed by the next step. |
| A request being sent | page.waitForRequest() |
Sending does not establish server success. |
| A particular API result | page.waitForResponse() |
Use a tight URL, method and status predicate. |
Reliability and performance considerations
Prefer event-driven waits over arbitrary sleeps. A fixed delay may be too short on a slow run and waste time on a fast one. Combine a lifecycle wait with one application-specific readiness check when necessary. Keep predicates narrow so unrelated analytics or background requests cannot release the script. Set realistic timeouts for the site’s latency, but treat timeout changes as tuning—not as a substitute for correct synchronization.
Navigation can be cancelled or replaced by another redirect, and pages with long polling may never reach a network-idle condition. In those cases, wait for the final URL pattern or a destination selector. If a site deliberately reloads during an action, place all post-action work after the reload’s navigation promise and reacquire every handle.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If your goal is a clean image or PDF rather than browser automation, ScreenshotNeo provides a single screenshot request. Its cleanup step accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets before capture; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the page verdict and billing result in X-Page-Verdict and X-Billed headers.
See the ScreenshotNeo documentation for all options, including full-page and element shots, device and retina settings, PDF output, custom CSS or JavaScript, waits, request blocking, cookies, headers, geolocation, caching, signed links, asynchronous jobs, bulk capture, usage and OpenAPI access.
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
An MCP server also lets Claude, Cursor and other MCP clients use take_screenshot, get_page_info and capture_pdf. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.
Frequently Asked Questions
Can this error occur without a visible URL change?
Yes. A reload, redirect, frame replacement, or document swap can destroy the context even when the final URL appears unchanged. Use the event that reflects the state your next step needs.
Should I catch the error and retry the same handle?
No. A retry using a handle tied to the replaced document is still stale. Wait for the destination state, query a fresh handle, and then retry the operation.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWhich wait should I use for a form that sometimes navigates and sometimes stays in place?
Model the two outcomes explicitly: use a navigation wait when the application guarantees a document transition; otherwise wait for the success or error selector, or for a tightly matched response. Do not add a navigation timeout merely because a submit button exists.
Quick Recap
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.

