skip to content

In a parallel Selenium run, cases throw NoSuchWindowException and failure screenshots show another test's page. What is the cause?

level: seniorimportance: must knowfreq 58%

answer

  1. Two symptoms, look for one cause
  2. Ask what both failing cases had in common
  3. The exception is about a browsing context
  4. Compare the session id across both failures
  5. One session served two threads at once

basics

~10 s

Two or more threads are driving one Selenium session. Both symptoms are the same fact: every thread's command lands in one browser whose window and page another thread has already changed underneath it.

solid answer

~50 s

That pairing is the signature of a shared driver, not of a flaky wait. In Selenium 4 a session is one conversation with one browser: the remote end keeps the current top-level browsing context per session id, and the W3C WebDriver protocol has nearly every command begin by returning `no such window` if that context is no longer open. So when one thread closes its window, the next command from any other thread on that session raises `NoSuchWindowException` — on a navigation or a find, not just on a window switch. The screenshot is the same mechanism seen from the other side: it captures whatever the one browser is showing at that instant, which is the other test's page. Confirm it by checking whether both failures carry the same `Session ID` in their exception details, then give each thread its own driver.

go deeper

for a junior

Recognise that an error about a missing window during a parallel run points at the driver setup rather than at the page under test, and know to check whether one driver is being reused.

for a middle

Explain the mechanism: the current top-level browsing context is per-session remote-end state, so another thread closing a window makes your next command fail regardless of which command it is.

for a senior

An interviewer expects a confirmation path, not a guess. Show how you compare session ids across failures, use the thread names the client sets during a command, and then name the structural fix.

for a principal

Own the standard that makes the class of failure impossible: how driver ownership is expressed so no shared reference exists, and how a suite proves isolation rather than trusting it.

## The two symptoms are the same fact A `NoSuchWindowException` and a screenshot of somebody else's page look like two unrelated flakes. They are one: **more than one thread is driving one Selenium session.** A session in Selenium 4 is a single conversation with a single browser, identified by one session id, and the remote end keeps that session's state — including its *current top-level browsing context* — on its own side. Two threads issuing commands against that id do not get two browsers. They get one, and each of them changes what the other's next command will act on. ## Why the exception is specifically NoSuchWindowException The W3C WebDriver protocol defines `no such window` as a 404 meaning "a command to switch to a window could not be satisfied because the window could not be found". Crucially, it is not raised only by window switching. The remote-end steps for almost every command begin with the same guard: *if the session's current top-level browsing context is no longer open, return error with error code `no such window`.* So the exception fires on a navigation, a find or a script call — any command at all — once that context has gone. What makes it go is another thread. Close Window is `DELETE /session/{session id}/window`, and the spec adds that if there are no more open top-level browsing contexts the remote end tries to close the session. So one thread finishing its case and closing its window leaves every other thread on that session with no context to act on, and the next command they send raises `NoSuchWindowException`. It appears "under load" because that is when two cases overlap; run the same two serially and the window is always there. ## Why the screenshot shows another test's page A failure screenshot captures the browser as it is at that instant, not as your case left it. If the shared browser was last navigated by a different thread, that is what lands in your report. This is the most misleading of the symptoms, because it makes the failing case look like it visited a page it never asked for — on a telecom **plan-comparison table** suite, the business-tariff comparison arrives attached to a prepaid case, and reviewers spend the morning on the page instead of on the driver. ## Confirming it quickly 1. **Compare the session ids in the two failures.** Every `WebDriverException` from the Java client carries a `Session ID` entry in its additional information, printed as `Session ID: <id>`. Two cases failing on the same id were served by one browser. 2. **Log the id at setup.** Call `getSessionId()` on the `RemoteWebDriver` in each thread's setup and assert the values are distinct across concurrently running cases. 3. **Wrap the driver in `ThreadGuard.protect(...)` for one run.** If it throws `Thread safety error; this instance of WebDriver was constructed on thread …`, the diagnosis is finished and the message names both threads. 4. **Read the thread names in the log.** `RemoteWebDriver.execute` renames the calling thread to `Forwarding <command> on session <id> to remote` for the duration of a command and restores it afterwards, so a log or a thread dump taken under load shows which threads were mid-command on which session. 5. **Find the sharing.** Look for a driver held in a `static` field, in a singleton, or created once in a class-level fixture that a per-case parallel runner then reuses. ## Symptom to mechanism | Symptom | Mechanism | What it is not | |---|---|---| | `NoSuchWindowException` on an ordinary command | another thread closed the session's current top-level browsing context | a window-switching bug in your own case | | Screenshot of a different test's page | one browser, last navigated by another thread | a broken screenshot helper | | `NoSuchSessionException` with `Session ID is null. Using WebDriver after calling quit()?` | another thread called `quit()` and nulled the shared client's session id | a driver crash | | Wrong values asserted, no exception at all | commands interleaved and the assertion read the other test's rows | a data-setup problem | ## What it is not, and what does not fix it - **Not a waiting problem.** No wait mechanism helps, because the wait would be polling a page that belongs to another test: it either times out or succeeds on the wrong content. - **Not Grid capacity.** Selenium's Grid node routes each request to the slot holding that session id and adds no locking of its own; a session that has genuinely gone reports `Cannot find session with id: …` instead. - **Not a retry candidate.** A rerun passes only because the timing changed, and a green retry can quietly hide an assertion that read another test's rows and happened to agree. - **Not a defect in the application.** It never saw two overlapping conversations; it answered one browser's requests exactly as they arrived. The fix is structural and small: one driver per thread, created and quit on that thread, with no shared reference for a second thread to reach.

  • Why does NoSuchWindowException appear on a find or a navigation rather than only on a window switch?
    Because the W3C WebDriver protocol puts the same guard at the top of nearly every command's remote-end steps: if the session's current top-level browsing context is no longer open, return `no such window`. Once another thread has closed that context, whichever command your thread happens to send next is the one that reports it.
  • How would you distinguish a shared driver from a driver whose browser genuinely crashed?
    A crash usually takes the whole session with it, so commands report a missing or unreachable session rather than a missing window, and every case on that worker fails together from that point on. A shared driver produces window and content errors that move between cases, with two different cases carrying the same `Session ID` in their exception details.
  • Why is a retry the wrong response to this failure pattern?
    Because a rerun changes only the timing. The two threads still share one browser, so the same interleaving reappears under different load, and in the meantime a passing retry can mask an assertion that read another test's data and happened to agree. The defect is structural and the fix is a driver per thread.

saying these in an interview costs you the question

  • Treats the pattern as a flaky wait and raises the timeout
  • Blames Grid capacity for an exception about a missing window
  • Assumes NoSuchWindowException can only come from a window switch
  • Reads the wrong-page screenshot as a broken screenshot helper
  • Retries the case until it passes without finding the shared reference