Puppeteer: Session closed. Most likely the page has been closed.
Last verified
Error: Protocol error (Runtime.callFunctionOn): Session closed. Most likely the page has been closed.What it means
Each page has its own DevTools session. When the page is closed, or the browser exits, that session is detached, and any command sent afterwards is rejected with this message. The method in parentheses is the command that was attempted, for example Runtime.callFunctionOn for an evaluate or Page.navigate for a goto.
In practice the page was closed by your own code or by the browser crashing. Missing await keywords are the classic cause: a function returns, browser.close() runs in a finally block, and an un-awaited page.evaluate() fails a moment later. Pages that call window.close() (OAuth popups) and memory-starved containers that kill renderer processes produce the same error.
What is not wrong: the evaluated code or selector. The target simply no longer exists.
What it looks like
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
page.on('close', () => console.warn('page closed'));
await page.goto('https://example.com/');
const title = await page.evaluate(() => document.title); // awaited
console.log(title);
} finally {
await browser.close();
}Why it happens
- An un-awaited Puppeteer call is still running when browser.close() or page.close() executes.
- Several tasks share one page and one of them closes it.
- The page closed itself (popup or OAuth window calling window.close()).
- The renderer or browser crashed, often from memory pressure in containers.
How to fix it
- Await every Puppeteer call and enable a no-floating-promises lint rule.
- Close pages and browsers only after all work using them has resolved.
- Give each concurrent task its own page, or its own browser context with browser.createBrowserContext().
- Listen for page.on('close') and browser.on('disconnected') to detect unexpected closes and log them.
- Increase container memory or reduce concurrency if the browser crashes under load.
How to stop it recurring
Structure scripts so the browser's lifetime visibly encloses every call, usually with try/finally and awaited calls only. Isolate concurrent work in separate pages or contexts. Monitor memory in containers, since renderer crashes show up as closed sessions rather than as obvious out-of-memory errors.
Official documentation: pptr.dev/api/puppeteer.page.close. See all Puppeteer error messages.
Related errors
Definitions
- PuppeteerPuppeteer is Google's open-source Node.js library for controlling Chrome and Firefox. It drives Chrome over th
- Chrome DevTools Protocol (CDP)The Chrome DevTools Protocol (CDP) is the JSON-over-WebSocket interface Chrome exposes for inspecting and cont
- CSS SelectorA CSS selector is a pattern used to identify and target specific HTML elements on a web page, widely used in b
- Headless ChromeHeadless Chrome is Google Chrome running without a visible window. It renders pages and runs JavaScript like n
- IframeAn iframe (inline frame) is an HTML element that embeds a separate web page within a parent page, creating an
- Web ElementA web element is any individual component rendered on a web page — buttons, links, input fields, images, text
Quick answers
What does "Session closed. Most likely the page has been closed." mean in Puppeteer?
Each page has its own DevTools session. When the page is closed, or the browser exits, that session is detached, and any command sent afterwards is rejected with this message. The method in parentheses is the command that was attempted, for example Runtime.callFunctionOn for an evaluate or Page.navigate for a goto . In practice the page was closed by your own code or by the browser crashing.
How do I fix "Session closed. Most likely the page has been closed."?
1. Await every Puppeteer call and enable a no-floating-promises lint rule. 2. Close pages and browsers only after all work using them has resolved. 3. Give each concurrent task its own page, or its own browser context with browser.createBrowserContext(). 4. Listen for page.on('close') and browser.on('disconnected') to detect unexpected closes and log them. 5. Increase container memory or reduce concurrency if the browser crashes under load.
Run browser automation you can watch and take over
Autonoly runs each job in a real cloud Chromium browser driven by Playwright. Timeouts and detached elements still happen; the difference is that you can watch the run live, see the step that failed, and take control of the browser to finish it.
Also see Live browser control.