puppeteer/puppeteer · error · Error
Execution context was destroyed, most likely because of a na
Error message
Execution context was destroyed, most likely because of a navigation.
What it means
rewriteEvaluationError catches the browser's raw 'ExecutionContext was destroyed' / 'Inspected target navigated or closed' messages and rewrites them into a human-readable form. It fires whenever a script evaluation runs against a realm/frame that no longer exists — almost always because the page navigated or was closed between scheduling and executing the function.
Source
Thrown at packages/puppeteer-core/src/bidi/util.ts:189
if (error instanceof ProtocolError) {
error.message += ` at ${message}`;
} else if (error instanceof TimeoutError) {
error.message = `Navigation timeout of ${ms} ms exceeded`;
}
throw error;
};
}
/**
* @internal
*/
export function rewriteEvaluationError(error: unknown): never {
if (error instanceof Error) {
if (
error.message.includes('ExecutionContext was destroyed') ||
error.message.includes('Inspected target navigated or closed')
) {
throw new Error(
'Execution context was destroyed, most likely because of a navigation.',
);
}
}
throw error;
}
View on GitHub (pinned to d484e21c17)
Solutions
- Re-acquire the page/frame handle after navigation before evaluating (waitForNavigation / waitForFunction).
- Use page.waitForFunction with the desired predicate instead of evaluate-after-click.
- Detect the navigation race and retry the evaluate on the new context.
- Avoid keeping ElementHandle references across navigations.
Example fix
// before await button.click(); // triggers navigation await page.evaluate(() => document.title); // after await Promise.all([ page.waitForNavigation(), button.click(), ]); await page.evaluate(() => document.title);
Defensive patterns
Strategy: retry
Validate before calling
// Acquire fresh context after navigation await page.waitForNavigation(); await page.evaluate(fn);
Type guard
const isContextDestroyed = (e) => e instanceof Error && /Execution context was destroyed/i.test(e.message);
Try / catch
try { return await page.evaluate(fn); } catch (e) { if (isContextDestroyed(e)) { await page.waitForFunction(fn); return; } throw e; } Prevention
- Pair click+navigation with waitForNavigation.
- Never reuse ElementHandles across navigations.
- Prefer waitForFunction over evaluate-after-action.
When it happens
Trigger: Calling page.evaluate / frame.evaluate / elementHandle.evaluate while a navigation is in flight; clicking an element whose handler triggers navigation, then awaiting a subsequent evaluate on the old context; awaiting evaluate after page.close().
Common situations: Race between a click that navigates and the next evaluate; SPA route changes that destroy the frame; reusing an ElementHandle after a navigation; calling evaluate on a frame whose page just redirected.
Related errors
- Error: failed to find element matching selector "${selector}
- Page is not found
- Trying to evaluate JSHandle from different frames. Usually t
- Execution context was destroyed, most likely because of a na
- Launch aborted
AI-assisted analysis of puppeteer/puppeteer@d484e21c17 (2026-08-12).
Data as JSON: /api/errors/3f2335944863630e.
Report an issue: GitHub.