# Playwright "Target page, context or browser has been closed": causes and fixes

> Why Playwright throws "Target page, context or browser has been closed" in locator.click, page.goto or browser.newContext, and how to fix each cause.

Published 2026-10-06, updated 2026-10-06. Canonical: https://turnsignal.ai/blog/playwright-target-page-context-or-browser-has-been-closed

## In short

- The error means an action was still waiting on a page, context or browser that had already been closed. The closing usually happened somewhere else; this line is where you noticed it.
- The most common cause is a missing `await`: the test ends, Playwright closes the page, and an action that was still running fails.
- Next are test timeouts (the page is closed while an action waits), pages kept between tests, and browsers that crash, often in Docker without `--ipc=host`.
- Read the line before it: the method name (`locator.click`, `page.goto`, `browser.newContext`) and any earlier timeout or crash message usually point to the cause.

## What the error means

Playwright raises this error when an operation needs a page, browser context or browser that no longer exists. It is prefixed with the call that was waiting, so you see it in forms like these:

```text
locator.click: Target page, context or browser has been closed
page.goto: Target page, context or browser has been closed
browser.newContext: Target page, context or browser has been closed
```

The method name tells you what was waiting, not what closed it. Something else closed the target first: the test finishing, a timeout, your own `close()` call, or a crash. Each has a different fix.

## Cause 1: a missing await

Playwright calls are asynchronous. Without `await`, the test function can return while the call is still running. Playwright then tears down the test, closes the page and its context, and the forgotten call fails with this error, sometimes in a later test's output:

```ts
test('saves the form', async ({ page }) => {
  await page.goto('/settings');
  page.getByRole('button', { name: 'Save' }).click(); // missing await
});
```

Add the `await`. To catch every case, Playwright's best practices recommend the `@typescript-eslint/no-floating-promises` ESLint rule, which flags calls whose promise is not awaited, and running `tsc --noEmit` in CI. Watch for the same bug in helpers: a function that calls Playwright must be `async`, and its callers must await it.

Event handlers are a variant of this. An `async` handler on `page.on('response')` that does more Playwright work can still be running after the test ends. Keep handlers synchronous, or collect what you need and await it inside the test.

## Cause 2: the test timed out

When a test hits its timeout (30 seconds by default), Playwright stops it and closes its page and context. An action that was still waiting, for example a click on an element that never became enabled, then fails with this error. In the output it appears together with `Test timeout of 30000ms exceeded`.

The real problem is the timeout. Open the trace and look at what the last action was waiting for. Raise the timeout only if the test is genuinely slow (`test.slow()` triples it for one test); otherwise fix the wait.

## Cause 3: the page or browser was closed by your code

Calling `page.close()`, `context.close()` or `browser.close()` while something still uses it gives the same error. Typical places:

- An `afterEach` or `afterAll` that closes a page that the test (or a forgotten promise) is still using.
- A test that clicks a link which closes the window or tab, then keeps using the old `page`.
- A `page` stored in a variable from one test and used in another. Playwright gives every test its own page; the old one is closed when its test ends.

If tests really must share a page, create it yourself in `beforeAll` and close it in `afterAll`, as Playwright's retries guide shows, and run those tests serially.

## Cause 4: the browser crashed

If the browser process crashes, every page and context in it is gone, and the next call fails with this error. In CI the usual reason is memory. Playwright's Docker guide says that without `--ipc=host`, Chromium can run out of memory and crash. Lowering `workers` in CI is a quick way to test the memory theory: if the error disappears with fewer workers, it was memory.

Look for other clues in the same run: `Target crashed`, `Page crashed`, or [`worker process exited unexpectedly`](https://turnsignal.ai/blog/playwright-worker-process-exited-unexpectedly) mean the process died rather than your code closing it.

## Cause 5: launching the browser failed

When the message comes from `browserType.launch` or `browser.newContext`, the browser may have closed while starting. Read the browser log Playwright prints under the error: missing system libraries, a sandbox problem in a container, or a browser version that does not match the installed Playwright. `npx playwright install --with-deps` installs the browsers and the system dependencies for the version you have.

## A quick checklist

1. Read the method in the prefix and the message just before it (timeout, crash, launch log).
2. Turn on `@typescript-eslint/no-floating-promises` and fix every finding.
3. If it comes with a test timeout, debug the timeout with the trace.
4. Search for `close()` calls and `page` variables shared between tests.
5. In CI, try fewer workers and `--ipc=host` in Docker to rule out memory.

## Is it new, or has it been happening for weeks?

This error is often intermittent: a missing `await` only fails when the timing is unlucky, and a memory crash only when the machine is busy. That makes it look like a flaky test. Knowing whether a failure is new on your branch, already happening on main, or a known flaky test saves a lot of guessing.

[TurnSignal](https://turnsignal.ai/) keeps each test's results across runs and branches. Every failure on a pull request is labelled **new**, **also failing on main** or **known flaky**, failures caused by a browser or worker crash are labelled as crashes, and the trace opens in the browser from the run page. The reporter never changes your exit code; setup is in the [docs](https://turnsignal.ai/docs).

## FAQ

**What causes "Target page, context or browser has been closed"?**

An action was waiting on a page, context or browser that was already closed. The usual causes are a missing `await`, a test timeout, a page closed by your own code, or a browser crash.

**Why do I get it together with "Test timeout of 30000ms exceeded"?**

When a test times out, Playwright closes its page and context. Any action still waiting then fails with this error. Fix the timeout; this line is a side effect.

**How do I find missing awaits in Playwright tests?**

Enable the `@typescript-eslint/no-floating-promises` ESLint rule, which Playwright recommends in its best practices, and run `tsc --noEmit` in CI.

**Can a browser crash cause this error?**

Yes. If the browser process dies, every page in it is closed. In Docker, run Chromium with `--ipc=host`, and try fewer workers to rule out memory.

## Sources

- [Playwright docs: Best practices (lint for missing awaits)](https://playwright.dev/docs/best-practices)
- [Playwright docs: Timeouts](https://playwright.dev/docs/test-timeouts)
- [Playwright docs: Retries (reusing a single page between tests)](https://playwright.dev/docs/test-retries)
- [Playwright docs: Docker (--ipc=host)](https://playwright.dev/docs/docker)
- [typescript-eslint: no-floating-promises](https://typescript-eslint.io/rules/no-floating-promises/)
