Skip to content
Playwright · error message

Playwright: Frame was detached

RetryableDetached elements, frames & contexts

Last verified

The exact message
Error: frame.click: Frame was detached

What it means

The Frame object your code was using has been removed from the page. Frames include iframes and the main frame of a page. When an iframe element is deleted, replaced, or reloaded by its parent in a way that creates a new frame, every pending and future call on the old Frame object fails with this message. Navigation errors can show a related form, such as net::ERR_ABORTED; maybe frame was detached? or Navigating frame was detached!.

The pattern is the same as with element handles: you grabbed a reference to a specific frame instance (for example via page.frame() or elementHandle.contentFrame()), and the page swapped it out. Payment widgets, embedded login forms, and ad iframes are frequent offenders because they rebuild themselves.

What is not wrong: the selector inside the frame. The container disappeared underneath it.

What it looks like

// Fragile: Frame object can be detached by a re-render
const frame = page.frame({ url: /checkout/ });
await frame.fill('#card', '4242424242424242');

// Robust: re-resolved on every call
const card = page.frameLocator('iframe[title="Secure card input"]');
await card.getByLabel('Card number').fill('4242424242424242');

Why it happens

  • The parent page removed and re-created the iframe, for example a payment widget re-rendering after validation.
  • A single-page app navigated and unmounted the component that held the iframe.
  • Code stored a Frame object from page.frames() and used it after a page navigation.
  • The iframe navigated to a URL that caused the browser to replace the frame.

How to fix it

  1. Use page.frameLocator('iframe[title="Payment"]') or locator.contentFrame(); these re-resolve the iframe on every action.
  2. Re-acquire Frame objects after any navigation instead of caching them.
  3. Wait for the iframe to be stable before interacting: await expect(page.locator('iframe[title="Payment"]')).toBeVisible().
  4. If the frame reloads as part of the flow, wait for the content you need inside the new frame rather than for the old one to respond.

How to stop it recurring

Never keep long-lived references to frames; address them by a stable attribute (title, name, src pattern) through frameLocator. Prefer locators throughout so both frames and elements are looked up fresh on each action. When a third-party widget is known to rebuild itself, assert on its final state before typing into it.

Official documentation: playwright.dev/docs/api/class-framelocator. See all Playwright error messages.

Related errors

Definitions

Quick answers

What does "Frame was detached" mean in Playwright?

The Frame object your code was using has been removed from the page. Frames include iframes and the main frame of a page. When an iframe element is deleted, replaced, or reloaded by its parent in a way that creates a new frame, every pending and future call on the old Frame object fails with this message. Navigation errors can show a related form, such as net::ERR_ABORTED; maybe frame was detached?

How do I fix "Frame was detached"?

1. Use page.frameLocator('iframe[title="Payment"]') or locator.contentFrame(); these re-resolve the iframe on every action. 2. Re-acquire Frame objects after any navigation instead of caching them. 3. Wait for the iframe to be stable before interacting: await expect(page.locator('iframe[title="Payment"]')).toBeVisible(). 4. If the frame reloads as part of the flow, wait for the content you need inside the new frame rather than for the old one to respond.

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.