Skip to content
Playwright · error message

Playwright: Target page, context or browser has been closed

Permanent - do not retryPage, context & browser lifecycle

Last verified

The exact message
Error: page.goto: Target page, context or browser has been closed

What it means

A call was made on a page, browser context or browser that no longer exists. Playwright raises this TargetClosedError for any API whose target was closed before or during the call, so the method name in front changes (page.goto, locator.click, page.waitForTimeout) but the cause is the same: something closed the object you were still using.

Very often the closer is your own code. In Node.js, the most common source is a missing await: the action is still running when the test ends or browser.close() runs, and the pending call then fails with this message. In Playwright Test, it also appears as the secondary error after a test timeout, because the runner tears down the page while your step is still waiting.

What is not wrong: the selector or URL. Look earlier in the output for the real failure; this message is frequently the second error, not the first.

What it looks like

// Bug: no await, so the test ends while click is pending
test('saves', async ({ page }) => {
  await page.goto('https://example.com/form');
  page.getByRole('button', { name: 'Save' }).click(); // missing await
});

// Fixed
test('saves', async ({ page }) => {
  await page.goto('https://example.com/form');
  await page.getByRole('button', { name: 'Save' }).click();
  await expect(page.getByText('Saved')).toBeVisible();
});

Why it happens

  • A missing await lets the test or script finish while an action is still pending.
  • browser.close(), context.close() or page.close() runs in a finally block or hook before outstanding work completes.
  • The test exceeded its timeout and the runner closed the page; this error is then reported alongside 'Test timeout of 30000ms exceeded.'
  • The browser process crashed, often from running out of memory or /dev/shm space in a container.
  • The site itself closed the tab, for example a popup that calls window.close() after login.

How to fix it

  1. Scroll up in the report: if a test timeout or another error precedes this one, fix that first.
  2. Enable the @typescript-eslint/no-floating-promises lint rule and add await to every Playwright call it flags.
  3. Move cleanup so it runs only after all actions have resolved; in Playwright Test let fixtures close pages instead of closing them manually.
  4. If you interact with a popup, capture it with const popup = await page.waitForEvent('popup') and stop using it once it closes.
  5. In Docker, launch with --ipc=host or a larger --shm-size, or pass args: ['--disable-dev-shm-usage'], to avoid Chromium crashes.

How to stop it recurring

Let the runner own the lifecycle: use the built-in page and context fixtures rather than launching and closing browsers by hand. Lint for floating promises so a forgotten await fails code review instead of a nightly run. In containers, use the official Playwright Docker image with --ipc=host, and listen for page.on('crash') to distinguish crashes from code-level closes.

Official documentation: playwright.dev/docs/api/class-page#page-event-close. See all Playwright error messages.

Related errors

Definitions

Quick answers

What does "Target page, context or browser has been closed" mean in Playwright?

A call was made on a page, browser context or browser that no longer exists. Playwright raises this TargetClosedError for any API whose target was closed before or during the call, so the method name in front changes ( page.goto , locator.click , page.waitForTimeout ) but the cause is the same: something closed the object you were still using. Very often the closer is your own code.

How do I fix "Target page, context or browser has been closed"?

1. Scroll up in the report: if a test timeout or another error precedes this one, fix that first. 2. Enable the @typescript-eslint/no-floating-promises lint rule and add await to every Playwright call it flags. 3. Move cleanup so it runs only after all actions have resolved; in Playwright Test let fixtures close pages instead of closing them manually. 4. If you interact with a popup, capture it with const popup = await page.waitForEvent('popup') and stop using it once it closes. 5. In Docker, launch with --ipc=host or a larger --shm-size, or pass args: ['--disable-dev-shm-usage'], to avoid…

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.