Puppeteer: Attempted to use detached Frame
Last verified
Error: Attempted to use detached Frame 'A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6'.What it means
A Frame object in Puppeteer represents one frame in the page tree: the main frame or an iframe. When that frame is removed from the page, Puppeteer marks the object as detached, and any later call on it (evaluate, $, click, waitForSelector, or calls on handles that belong to it) throws this error. The quoted value is Chrome's internal frame ID.
It appears in two situations. With iframes, the embedding page removed or rebuilt the iframe, which is common with payment fields, captcha widgets and ads. With the main frame, it usually means the whole page or tab was closed or swapped, often because the script kept using a page object after the site opened a new tab and closed the old one, or after the browser crashed.
What is not wrong: the selector or code you were running inside the frame.
What it looks like
async function payFrame(page) {
const el = await page.waitForSelector('iframe[name="card"]', { visible: true });
return el.contentFrame();
}
const frame = await payFrame(page);
await frame.locator('input[name="cardnumber"]').fill('4242424242424242');Why it happens
- The parent page removed or replaced the iframe (widget re-render, route change).
- A Frame obtained from page.frames() or contentFrame() was cached and used after a navigation.
- The page or tab owning the frame was closed or crashed.
- Concurrent tasks share a page and one of them navigated it away.
How to fix it
- Re-acquire the frame right before using it, from the iframe element: await (await page.waitForSelector('iframe#pay')).contentFrame().
- After any navigation, discard old Frame objects and look them up again.
- Use page.on('framedetached') to log when and which frames disappear.
- Give concurrent tasks separate pages so one task's navigation cannot detach another's frames.
How to stop it recurring
Look frames up by a stable attribute every time you need them instead of storing Frame objects. Wait for third-party widgets to finish rendering before typing into them. If a site opens new tabs, track them with browser.waitForTarget() and switch explicitly.
Official documentation: pptr.dev/api/puppeteer.frame. 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 "Attempted to use detached Frame" mean in Puppeteer?
A Frame object in Puppeteer represents one frame in the page tree: the main frame or an iframe. When that frame is removed from the page, Puppeteer marks the object as detached, and any later call on it ( evaluate , $ , click , waitForSelector , or calls on handles that belong to it) throws this error. The quoted value is Chrome's internal frame ID. It appears in two situations.
How do I fix "Attempted to use detached Frame"?
1. Re-acquire the frame right before using it, from the iframe element: await (await page.waitForSelector('iframe#pay')).contentFrame(). 2. After any navigation, discard old Frame objects and look them up again. 3. Use page.on('framedetached') to log when and which frames disappear. 4. Give concurrent tasks separate pages so one task's navigation cannot detach another's frames.
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.