Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

NoSuchWindowException: no such window: target window already closed means Selenium is trying to use a top-level browser window or tab that no longer exists. The reliable fix is to inspect the window operations immediately before the failure, compare the saved handle with getWindowHandles(), switch only to a live handle, and start a new WebDriver session if every top-level context has been closed.

This error is often described as “no such window,” “web view not found,” or “error while switching to main window.” The wording varies by browser and language binding, but the underlying condition is the same: the command targets a browsing context that is unavailable.

What Selenium window handles represent

A Selenium window handle identifies one top-level browsing context: a browser window or tab. The WebDriver protocol exposes separate commands to get the current handle, list all open handles, switch to a handle, and close the current context. A handle is usable only while that context remains open.

Handle values are identifiers, not positions. The order returned by getWindowHandles() is arbitrary, so index zero is not guaranteed to be the “main window,” and the last item is not guaranteed to be the newest tab. This behavior is described in the W3C WebDriver editor’s draft and the WebdriverIO WebDriver protocol documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Find the operation that closed the context

Start with the failing line in the stack trace, then inspect the window commands immediately before it. The most common causes are:

  • Your test called driver.close() while the driver was focused on the window you later tried to use.
  • A popup, authentication tab, or application workflow closed itself.
  • A loop closed the original window accidentally while iterating through handles.
  • Cleanup code ran earlier than expected.
  • The last remaining top-level context was closed, ending the session.

Capture the current handle and complete handle set around every open, switch, and close operation while diagnosing:

  • Java: driver.getWindowHandle() and driver.getWindowHandles()
  • Python: driver.current_window_handle and driver.window_handles
  • JavaScript/WebdriverIO: getCurrentWindowHandle() and getWindowHandles()

Log the values before opening a new tab, after it opens, before closing a context, and immediately before switching back. This reveals whether the intended handle disappeared or whether the new context never appeared.

Use a handle-safe switching pattern

Java (Selenium 4)

String original = driver.getWindowHandle();
Set<String> before = driver.getWindowHandles();

// Perform the action that opens a tab or window.
driver.findElement(By.cssSelector("a[target='_blank']")).click();

Set<String> after = driver.getWindowHandles();
String child = after.stream()
    .filter(handle -> !before.contains(handle))
    .findFirst()
    .orElseThrow(() -> new IllegalStateException("No new window opened"));

driver.switchTo().window(child);
// Work in the child context.

Set<String> live = driver.getWindowHandles();
if (live.contains(original)) {
    driver.switchTo().window(original);
} else if (!live.isEmpty()) {
    driver.switchTo().window(live.iterator().next());
} else {
    throw new IllegalStateException("All top-level windows are closed; create a new driver session");
}

Comparing the sets identifies the newly opened context without relying on ordering. Before switching back, the code confirms that the original handle is still live.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Python

from selenium import webdriver
from selenium.webdriver.common.by import By

original = driver.current_window_handle
before = set(driver.window_handles)

driver.find_element(By.CSS_SELECTOR, "a[target='_blank']").click()

after = set(driver.window_handles)
new_handles = after - before
if not new_handles:
    raise RuntimeError("No new window opened")

child = next(iter(new_handles))
driver.switch_to.window(child)
# Work in the child context.

live = set(driver.window_handles)
if original in live:
    driver.switch_to.window(original)
elif live:
    driver.switch_to.window(next(iter(live)))
else:
    raise RuntimeError("All top-level windows are closed; create a new driver session")

JavaScript (WebdriverIO)

const original = await browser.getCurrentWindowHandle();
const before = new Set(await browser.getWindowHandles());

await $('a[target="_blank"]').click();
const after = await browser.getWindowHandles();
const child = after.find(handle => !before.has(handle));
if (!child) throw new Error('No new window opened');

await browser.switchToWindow(child);
// Work in the child context.

const live = await browser.getWindowHandles();
if (live.includes(original)) {
  await browser.switchToWindow(original);
} else if (live.length) {
  await browser.switchToWindow(live[0]);
} else {
  throw new Error('All top-level windows are closed; create a new browser session');
}

What to do after driver.close()

close() closes the current top-level context. If another window remains, the session can continue, but Selenium is no longer guaranteed to be focused on the context your test originally called “main.” Retrieve the live handles and explicitly switch to the one you want.

If the closed context was the last one, closing it closes the WebDriver session. No later switch can revive that handle. End the test’s driver object and create a fresh session through the same setup path used at test start. Do not keep retrying switchTo().window() against the dead handle.

Recovery decisions

Intended handle in current live list? Other live handles? Action
Yes Not relevant Switch to the intended handle and continue.
No Yes Select a known surviving handle, switch to it, and adjust the test’s state; do not assume it is the original window.
No No The session has no top-level contexts. Start a new WebDriver session through normal test setup.

This is the practical form of the handle-checking recovery strategy discussed in Selenium issue #17882.

Prevent accidental window closure

Keep ownership of handles explicit

Store the original handle once, but validate it every time you return to it. When a helper opens a tab, have the helper return the new handle rather than hiding it in global state.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Close only the context you intend to close

Before calling close(), log the current handle and URL. If a loop must close several tabs, make a copy of the live handle collection and skip the handle that must remain open. Never use list position as a proxy for identity.

Wait for a new handle, not an arbitrary sleep

Applications may create a tab asynchronously. Poll until the handle set contains a value not present before the click, with a timeout appropriate to your test environment. A fixed sleep can be too short on a busy runner and unnecessarily slow on a fast one.

Separate browser cleanup from test actions

Ensure teardown hooks do not run while another test step is still executing. In parallel test suites, each test should own its WebDriver session unless your framework explicitly supports safe sharing.

When the error occurs during startup

If the first failing command is a startup call such as obtaining the current window handle, inspect the complete environment rather than assuming a prior close(). Record:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Selenium language binding and version
  • Browser name and version
  • Browser-driver version
  • Operating system and architecture
  • The exact failing command and preceding log lines
  • Whether the browser process remained open or exited immediately

Compare browser and driver compatibility, then reproduce with a minimal session. A report in Selenium issue #13791 lists Selenium 4.19.1, Chrome 123, ChromeDriver 123, and a warning that the closest CDP match was version 121; it documents that environment and a getCurrentWindowHandle failure, but it does not establish that every CDP warning causes a closed-window exception. Treat version warnings as diagnostic clues, not proof of causation.

Troubleshooting common symptoms

“No such window” immediately after switching

The target handle may have been closed between collecting handles and switching. Re-read the live handle list immediately before the switch and choose only a value still present. If the application closes the tab quickly, change the workflow so assertions run before the close.

“Web view not found” in a mobile or embedded environment

The selected web view may have disappeared or the automation context may have changed. Enumerate currently available contexts using the binding’s context API, then select an extant context. Do not treat a stale context name as reusable.

The original window is missing after a popup test

Check whether popup cleanup closed the original instead of the child. The live-handle set determines what survives; variable names such as mainWindow do not.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

All handles disappear

The last top-level context was closed, so the session is over. Create a new driver. Retrying with the old object cannot restore a closed browsing context.

The failure is intermittent

Add timestamped logs for handle sets, current handle, URL, title, and every close operation. Replace sleeps with waits for the expected handle-set change. Intermittence usually indicates a race between application behavior, cleanup, and the next switch; the logs identify which event won.

Performance and reliability considerations

Reading the handle list is inexpensive compared with page navigation, but excessive polling can still add delay. Poll at a sensible interval, stop as soon as the expected handle appears, and set a bounded timeout. Keep the number of open tabs small: each context consumes browser resources and increases the chance that cleanup logic targets the wrong one.

For reliable tests, make each window transition observable: capture the before-and-after handle sets, identify the new handle by set difference, perform work, verify the target still exists before returning, and close only a deliberately selected context. If no context remains, fail clearly and let the framework recreate the session rather than masking the original error with repeated switch attempts.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

If your goal is to capture a page image or PDF rather than interact with multiple browser contexts, ScreenshotNeo provides a single HTTP request and an MCP server for AI agents. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; those steps can be disabled individually. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status.

See the ScreenshotNeo API documentation for all options. A direct cURL request is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The equivalent Python request is:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

And Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or custom viewports, retina scale, PDF paper and margin controls, HTML/CSS-to-image, custom CSS and JavaScript, clicks, selector or network-idle waits, request and resource blocking, headers, cookies, user agents, Authorization, timezone and geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Common screenshot-API parameter names also work when migrating.

The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. Create a free ScreenshotNeo account to begin.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

FAQ

Can I recreate a closed Selenium handle?

No. A handle identifies a live top-level context. Once that context is closed, switch to another live handle or create a new session if none remain.

Is the first handle always the main window?

No. Handle order is arbitrary. Identify contexts by set difference, URL, title, or another application-specific property.

Does a CDP warning prove it caused this exception?

No. The reported Selenium issue shows a warning and a failure in one environment, not a universal causal rule.

Frequently Asked Questions

Can I recreate a closed Selenium handle?

No. A handle identifies a live top-level context. Once that context is closed, switch to another live handle or create a new session if none remain.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Is the first handle always the main window?

No. Handle order is arbitrary. Identify contexts by set difference, URL, title, or another application-specific property.

Does a CDP warning prove it caused this exception?

No. The reported Selenium issue shows a warning and a failure in one environment, not a universal causal rule.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.