Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →“Execution context was destroyed, most likely because of a navigation” means Puppeteer was evaluating JavaScript in a document that the browser replaced. The reliable fix is to coordinate navigation with the action that triggers it, wait for a condition that proves the list is ready, and only then query the current document. Do not treat a visible container or an arbitrary sleep as proof that every item has loaded.
What the error means
Each page in Puppeteer has an execution context associated with its current document. Calls such as page.evaluate(), page.waitForFunction(), and operations on element handles run in that context. A full navigation, reload, redirect, history navigation, or some site-triggered navigation destroys the old document and creates a new one. If an evaluation is still in flight when that replacement occurs, Puppeteer reports the context-loss error.
This is a lifecycle symptom, not proof of a Puppeteer defect. A reported list-loading issue with this message was closed as needs-feedback and not-reproducible; it does not establish the exact cause on another site. The remedy must therefore be based on the target site’s navigation and data-loading behavior.
Use the correct sequence before extracting items
1. Pair a navigation-triggering action with its wait
Register the navigation wait before clicking or submitting. Starting the wait afterward can miss a fast navigation.
#1 Best Overall
- Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
- Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
- Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
- Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
- 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
const [response] = await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.click('a.next-page'),
]);
// The response can be null for a same-document History API navigation.
// Continue by waiting for the list's own ready condition.
Puppeteer’s reference demonstrates this Promise.all ordering. A History API URL change still counts as navigation, and its navigation response may be null. Select waitUntil for the site: domcontentloaded confirms the HTML document is parsed, not that client-side requests have rendered all rows.
2. Await direct navigation, then wait for application state
await page.goto('https://example.com/products', {
waitUntil: 'domcontentloaded',
});
// Follow with a condition that means “the list is ready” for this site.
await page.waitForSelector('.products-loaded', {
visible: true,
timeout: 30_000,
});
page.goto() follows redirects and resolves with the last redirect’s response. It does not wait for asynchronous JavaScript data loading. A selector wait is useful only when that selector represents the state you need; the presence of a container alone may occur before its children arrive.
3. Wait for a known minimum count when you truly know it
const expectedCount = 20;
await page.waitForFunction(
count => document.querySelectorAll('.container > li').length >= count,
{},
expectedCount,
);
const items = await page.$$eval('.container > li', nodes =>
nodes.map(node => node.textContent?.trim() ?? '')
);
console.log(items);
waitForFunction resolves when its predicate becomes truthy and supports polling, timeout, and cancellation options. A minimum count is appropriate only when the expected count is known and meaningful. If the site can legitimately return fewer rows, this predicate can wait forever or conceal a legitimate empty result.
4. For an unknown count, wait for the site’s completion signal
There is no universal selector or timeout that identifies the end of an unknown list. Use the application’s actual contract, such as:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problems- a loading indicator disappearing after the final request;
- an “end of results” marker appearing;
- a “Load more” button becoming disabled or disappearing;
- a pagination control reporting that the final page is active;
- a specific data request completing and the UI reflecting its response.
Choose the predicate from the site’s behavior. An issue that asks how to handle an unknown list size does not provide enough information to name one reliable selector.
// Example: the site removes its spinner only after all rows are rendered.
await page.waitForSelector('[data-testid="list-spinner"]', {
hidden: true,
timeout: 30_000,
});
const items = await page.$$eval('[data-testid="result-row"]', rows =>
rows.map(row => ({
title: row.querySelector('.title')?.textContent?.trim() ?? '',
href: row.querySelector('a')?.href ?? '',
}))
);
The selector names above are examples. Replace them with states your application guarantees. Puppeteer’s waitForSelector() documentation states that the method works across navigations, but that statement does not mean it detects list completeness.
Rank #2
- 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
- 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
- Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
- 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
- What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
Extract from the current document, not stale handles
Element handles and JavaScript references belong to the document in which they were created. After navigation, discard them and query again. A single $$eval run after readiness keeps selection and mapping in the current page context:
async function readRows(page) {
return page.$$eval('.container > li', nodes =>
nodes.map(node => node.textContent?.trim() ?? '')
);
}
await page.goto('https://example.com/list', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('.list-finished', { timeout: 30_000 });
const rows = await readRows(page);
This pattern reduces the time in which a navigation can invalidate a reference; it cannot prevent a concurrent navigation. If the page can navigate while extraction runs, first wait for the site’s terminal state or guard the operation with your own navigation coordination.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallPagination and detail-page loops
Process each page only after its readiness condition, and verify that pagination actually advanced. Do not assume that a successful click means new rows are present.
async function collectPage(page) {
await page.waitForSelector('[data-list-ready="true"]', { timeout: 30_000 });
return page.$$eval('.result-row', rows =>
rows.map(row => row.textContent?.trim() ?? '')
);
}
const all = [];
for (;;) {
all.push(...await collectPage(page));
const next = await page.$('a.next-page:not([aria-disabled="true"])');
if (!next) break;
const previousUrl = page.url();
await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
next.click(),
]);
// For an in-page update, replace the navigation wait with the site's
// loading/completion predicate and verify that state changed.
if (page.url() === previousUrl) {
throw new Error('Next-page action did not advance the URL');
}
}
If navigation is implemented with an in-page framework update rather than a document load, waitForNavigation() may not be the right completion signal. Wait for the framework’s loading marker, request completion, or newly rendered page state instead.
Diagnosis checklist
- Identify every possible document change:
goto, reload, link click, form submission, redirect,goBack(), and site-triggered navigations. - Register waits first: put
waitForNavigation()and the triggering action in onePromise.all. - Match the wait to the need: use
waitForSelector()for presence, visibility, or disappearance; usewaitForFunction()for counts or application predicates. - Set a bounded timeout: the current selector API defaults to 30 seconds and permits configuration. A timeout should expose the URL, predicate, and count observed so the failure is diagnosable.
- Re-query after navigation: never reuse an element handle captured from the old document.
- Prefer observable state to sleeps: a fixed delay has no universal meaning and does not encode whether the list is complete.
Common failures and fixes
The wait is registered after the click
Symptom: intermittent timeout or context loss immediately after clicking.
Fix: start waitForNavigation() in the same Promise.all as the click, with the wait expression listed first.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #3
- Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
- Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
- Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
- Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
- What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
domcontentloaded fires but rows are missing
Cause: the page’s scripts fetch data after the document event.
Fix: add a list-specific completion predicate, such as a spinner disappearing or an end marker appearing.
waitForSelector('.container') succeeds too early
Cause: the container exists before its children are rendered.
Fix: wait for a child count, a ready attribute, a terminal marker, or the request/UI state that the application uses to signal completion.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Waiting for a guessed count never finishes
Cause: the result set can contain fewer items, or pagination loads an unknown number.
Fix: use the site’s end-of-data signal. If no such signal exists, define one in the application or stop after a verified pagination condition rather than inventing a delay.
Rank #4
- Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
- Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
- Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
- Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
- Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
goBack() returns to a page but handles fail
Cause: returning creates or restores a document context; handles from the detail page or previous list document are not safe to reuse.
Fix: await the back navigation, wait for list readiness again, and select fresh handles.
Extraction races a second navigation
Cause: an auto-refresh, redirect, or user-script navigation occurs during $$eval.
Fix: wait for a stable terminal state, disable the triggering behavior where appropriate, or catch the failure and retry the whole readiness-and-extraction sequence—not just the stale evaluation.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Timeouts, cancellation, and observability
Keep waits finite and log enough context to reproduce a failure:
try {
await page.waitForFunction(
() => document.querySelectorAll('.result-row').length > 0,
{ timeout: 15_000 },
);
} catch (error) {
const count = await page.$$eval('.result-row', rows => rows.length)
.catch(() => -1);
console.error({ url: page.url(), count, error });
throw error;
}
For production crawlers, record the URL, navigation target, wait type, timeout, current count, and whether the page reported an end condition. These fields distinguish a selector mismatch from a slow API, a redirect loop, and a genuine context replacement.
Best Value
- 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.
Version compatibility
The API patterns described here match the Puppeteer documentation observed for version 25.12.0. Check the version installed by your project before copying options into an older codebase; defaults and supported parameters can differ. The central lifecycle rule remains the same: coordinate navigation, wait for meaningful page state, then evaluate against the current document.
Or skip the browser setup
If your goal is a clean image or PDF rather than interactive scraping, ScreenshotNeo can handle the capture with one request. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
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 all options, including waits and selectors.
ScreenshotNeo includes full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper settings and page ranges, custom CSS and JavaScript, clicks, selector hiding, selector/delay/network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture for 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work.
The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan. Create a free ScreenshotNeo account.
What to remember
- Context destruction indicates that the document changed while an operation was using it.
- Pair navigation-causing actions with a navigation wait registered first.
- After
goto()or a click, wait for the application’s real list-ready condition. - For unknown list sizes, use an end marker, disabled pagination, request completion, or another site-specific terminal signal.
- Extract with fresh queries from the current document and treat timeouts as diagnostic data.
Frequently Asked Questions
Does increasing the timeout fix execution-context destruction?
No. A longer timeout can accommodate slow loading, but it cannot make an old document context valid. Coordinate navigation and re-query after the new document is ready.
Should I use network idle to know that every list item loaded?
Not automatically. Network idleness is only meaningful if that site’s data contract makes it a reliable completion signal. Prefer a site-specific marker, count, or request/UI state.
Can I choose one generic selector for every unknown list?
No. Selector names and completion signals depend on the application. A container selector proves presence of the container, not completion of its children.
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.

