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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

The Selenium error NoSuchWindowException: no such window: target window already closed means your command is targeting a top-level browser window or tab that no longer exists. The reliable fix is to inspect which handles are still open, switch only to a live handle, and create a new WebDriver session if every top-level context has been closed.

What the error means

Selenium represents each top-level browser window or tab with a window handle. Commands such as getWindowHandle, getWindowHandles, switchTo().window(...), and close() operate on those browsing contexts. A handle is usable only while its associated context remains open; switching to a closed handle raises the exception shown above. The WebDriver protocol defines these operations in its current editor’s draft at W3C WebDriver.

Closing the last top-level context also ends the WebDriver session. At that point, no later switch can revive the session; your test framework must construct a new driver through its normal setup path.

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

Fast diagnosis

  1. Locate the failing command in the stack trace. Note whether it is a switch, a current-handle query, navigation, or another command that ran after a window operation.
  2. Inspect the immediately preceding code for driver.close(), popup-cleanup logic, an application action that closes a tab, or a loop that may be closing the original window.
  3. Log the current handle and the complete handle set before opening and closing contexts.
  4. Compare the saved handle with the fresh list returned by getWindowHandles(). Never assume the list order identifies the “main” window or the newest tab; WebDriver does not guarantee a meaningful order.

Minimal logging example (Java)

System.out.println("current=" + driver.getWindowHandle());
System.out.println("open=" + driver.getWindowHandles());

Run the logging immediately before the failing switch and immediately after every close. This usually reveals that the intended handle has disappeared earlier than expected.

Handle-safe window switching

Capture the original context

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

// Trigger the link, button, or script that opens another tab here.

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

driver.switchTo().window(newHandle);

The set difference identifies a newly appearing context without relying on arbitrary handle order. If several contexts can open, identify the target by title, URL, or a page-specific element after switching, and close only the context you have verified.

Return only if the original still exists

Set<String> liveHandles = driver.getWindowHandles();
if (liveHandles.contains(original)) {
    driver.switchTo().window(original);
} else if (!liveHandles.isEmpty()) {
    String surviving = liveHandles.iterator().next();
    driver.switchTo().window(surviving);
} else {
    driver.quit();
    // Let the test framework's setup method create a fresh driver.
    throw new IllegalStateException("All top-level windows are closed");
}

This is the essential recovery decision: switch to the saved handle when it remains, choose a known surviving context when it does not, and stop using the session when no contexts remain. Selenium issue #17882 describes this style of existence check in a Java case reported on 6 August 2026.

Correctly closing tabs and windows

Use close() only for the current context

driver.close() closes the currently selected top-level context. It does not automatically switch you to another handle. Therefore, a loop that closes a popup and then immediately calls switchTo().window(savedHandle) will fail if the saved handle was also closed, or if the popup was the last remaining context.

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.
String popup = driver.getWindowHandle();
// ... switch to popup and finish its work ...
driver.close();

Set<String> remaining = driver.getWindowHandles();
if (remaining.contains(original)) {
    driver.switchTo().window(original);
} else if (!remaining.isEmpty()) {
    driver.switchTo().window(remaining.iterator().next());
} else {
    driver.quit();
}

Prefer a deliberate lifecycle

  • Use close() when you intend to close one tab or window.
  • Use quit() during teardown to close the entire browser and end the session.
  • Do not call close() in a loop over handles unless you have explicitly excluded the context you still need.
  • After an application closes a tab unexpectedly, refresh the live handle set before attempting any switch.

Python and JavaScript equivalents

Python

from selenium import webdriver

 driver = webdriver.Chrome()
original = driver.current_window_handle
before = set(driver.window_handles)
# Trigger the action that opens a tab here

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

new_handle = next(iter(new_handles))
driver.switch_to.window(new_handle)

# After closing the child:
driver.close()
live = set(driver.window_handles)
if original in live:
    driver.switch_to.window(original)
elif live:
    driver.switch_to.window(next(iter(live)))
else:
    driver.quit()
    raise RuntimeError("All top-level windows are closed")

Remove the accidental leading space before driver if you paste this into a file; Python indentation must be consistent.

JavaScript with selenium-webdriver

const {Builder} = require('selenium-webdriver');

(async function () {
  const driver = await new Builder().forBrowser('chrome').build();
  const original = await driver.getWindowHandle();
  const before = new Set(await driver.getAllWindowHandles());

  // Trigger the action that opens a tab here.
  const after = new Set(await driver.getAllWindowHandles());
  const newHandle = [...after].find(h => !before.has(h));
  if (!newHandle) throw new Error('No new window opened');

  await driver.switchTo().window(newHandle);
  // ... work in the child ...
  await driver.close();

  const live = await driver.getAllWindowHandles();
  if (live.includes(original)) {
    await driver.switchTo().window(original);
  } else if (live.length) {
    await driver.switchTo().window(live[0]);
  } else {
    await driver.quit();
    throw new Error('All top-level windows are closed');
  }
})();

When the failure occurs during startup

If the exception appears before your test intentionally opens or closes a tab, collect the Selenium binding version, browser version, driver version, operating system, complete stack trace, and the exact failing command. Compare those versions using the compatibility guidance for your browser and driver, but treat warnings as clues rather than proof of causation.

Selenium issue #13791 records one environment with Selenium 4.19.1, Chrome 123, ChromeDriver 123, and a warning that the closest Chrome DevTools Protocol match was version 121. Its failing command was getCurrentWindowHandle. That report establishes what happened in that case; it does not show that every CDP warning causes a closed-window exception.

Recovery decision table

Saved handle present? Any live handles? Action
Yes Yes Switch to the saved handle.
No Yes Switch to a verified surviving context and re-establish the test state.
No No End the session and create a new WebDriver instance through normal setup.

Common causes and fixes

The original window was closed accidentally

A cleanup helper may call close() while the original handle is selected. Log the selected handle before closing and exclude the handle that owns the rest of the test.

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

The application closed a popup

Some authentication, payment, or download flows close their own tab. Do not assume the child survives until your cleanup code runs. Re-read getWindowHandles() after the application action.

A loop uses handle position

Code such as “the first handle is the main window” is fragile because handle order is arbitrary. Store the original value and compare sets instead.

A stale saved handle is reused across tests

Window handles belong to a particular browser session. Do not persist one between tests or after quit(). Capture handles during setup for the current session.

All contexts were closed

There is no in-session repair. Mark the test as requiring a fresh driver, run teardown safely, and let the fixture create a new session.

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.

Startup versions or driver launch problems

Capture versions and startup logs first. A browser-driver mismatch, a failed launch, or an infrastructure problem may be involved, but the closed-window text alone cannot identify the cause.

Waits, timing, and reliability

Explicit waits can prevent a race in which your code switches before a new tab is actually registered, but a wait cannot make a closed handle live again. Wait for a measurable condition such as the number of handles increasing, then compute the set difference:

WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(d -> d.getWindowHandles().size() > before.size());
Set<String> after = driver.getWindowHandles();

Use a bounded timeout and include the observed handles in failure diagnostics. Avoid arbitrary sleeps as the only synchronization method; they slow successful runs and still fail under variable load.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is simply to obtain a clean image or PDF of a page rather than interact with multiple Selenium contexts, ScreenshotNeo provides a single HTTP request. It accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.

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

Use the API documentation at screenshotneo.com/docs/ for all options. A 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 same request in Python:

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 in 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 also has an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Its free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Further reading

Frequently Asked Questions

Can I reopen a Selenium window after calling close()?

No. A closed top-level context cannot be reopened through its old handle. Switch to a surviving handle or start a new WebDriver session if none remain.

Why should I avoid using the first item in getWindowHandles()?

The WebDriver protocol does not define an order for returned handles, so position does not reliably mean the original window or newest tab.

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

Does a CDP version warning prove it caused this exception?

No. A Selenium issue reports both a CDP warning and this exception in one environment, but that is not evidence that the warning is universally causal.

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.