skip to content

A Selenium test fails with UnhandledAlertException and the confirm dialog is gone by the time you look. Why?

level: seniorimportance: must knowfreq 52%

answer

  1. Something answered it before you looked
  2. A session-wide default, not your test
  3. The failing command was not the alert
  4. Dismiss and notify
  5. The unhandledPromptBehavior capability

basics

~10 s

Selenium 4 sessions default to the dismiss and notify prompt handler, so the remote end dismissed the dialog and then failed that command with UnhandledAlertException. Nothing lost the dialog; the default answered it.

solid answer

~40 s

Every WebDriver command except the alert commands themselves begins with a handle any user prompts step. In Selenium 4 a session's `unhandledPromptBehavior` defaults to `dismiss and notify`, so a command that finds a dialog open has it dismissed for it and then returns the `unexpected alert open` error, which the Java client raises as `UnhandledAlertException`. That is why the dialog has vanished, and why `UnhandledAlertException.getAlertText()` is often the only record of what it said. The failing command is the victim, not the cause: the trigger is the action on the line before. The fix is to expect the dialog — take `driver.switchTo().alert()`, assert `getText()`, then `accept()` or `dismiss()` deliberately. A blanket `accept` or `dismiss` handler only buys silence, and `ignore` leaves the dialog open so every later command fails the same way.

code

java · 10 lines
java
driver.findElement(By.id("place-order")).click();
Alert confirm = driver.switchTo().alert();
String text = confirm.getText();
if (text.contains("Charge your card")) {
  confirm.accept();
} else {
  confirm.dismiss();
  throw new AssertionError("Unexpected checkout dialog: " + text);
}
driver.findElement(By.id("order-number"));

go deeper

for a junior

Be ready to say what a confirm dialog is and that a test answers one through the alert switch. Recognising the name UnhandledAlertException, and knowing some other command reported it, is enough at this stage.

for a middle

Explain the handle any user prompts step: every command except the alert commands checks for an open dialog first, and the dismiss and notify default closes the dialog before failing that command.

for a senior

Show the diagnosis: read the alert text off the exception, look at the action on the line before the failure, and make the suite answer expected dialogs deliberately rather than muting them with a blanket handler.

for a principal

Own the policy. Decide whether a suite ever runs on a non-default prompt handler, how an unexpected dialog is surfaced rather than swallowed, and who answers for a confirm that silently cancelled a customer's paid order.

## What the exception actually reports `UnhandledAlertException` is the Java client's name for the W3C WebDriver error **`unexpected alert open`**. It is not raised by the dialog appearing, and it is not raised by `driver.switchTo().alert()`. It is raised by *some other command* that ran while a **user prompt** — a `window.alert`, a `window.confirm`, a `window.prompt`, or a `beforeunload` prompt — was on screen. Almost every WebDriver command begins with a **handle any user prompts** step. Before finding an element, clicking, reading the current URL or executing script, the remote end checks whether a prompt is open and applies the session's **prompt handler**. Only the four alert commands skip that step — Get Alert Text, Send Alert Text, Accept Alert and Dismiss Alert, reached in Java through `driver.switchTo().alert()` — because they are how a prompt gets answered at all. ## How a bookshop checkout produces it 1. The test clicks **Place order**, and the page runs `confirm("Charge your card for 3 books?")`. 2. The test's next line, `driver.findElement(By.id("order-number"))`, reaches the remote end. 3. That command runs handle-any-user-prompts, finds the confirm open, and applies the session's handler. 4. The default handler **dismisses** the dialog and then fails the command with `unexpected alert open`, which the Java client throws as `UnhandledAlertException`. By the time anyone inspects the run, the dialog is gone — and because it was dismissed rather than accepted, `confirm` returned `false` to the page, so no order was ever placed. The real defect, an unexpected confirmation step in the checkout flow, sits one line earlier than the stack trace suggests. ## The five prompt-handler values In Selenium 4 the handler is fixed for the session by the **`unhandledPromptBehavior`** capability negotiated when the session is created. The defined values are: | Value | What the remote end does | What the running command sees | |---|---|---| | `dismiss` | Dismisses the prompt silently | The command proceeds normally | | `accept` | Accepts the prompt silently | The command proceeds normally | | `dismiss and notify` | Dismisses it, then fails the command | `UnhandledAlertException` | | `accept and notify` | Accepts it, then fails the command | `UnhandledAlertException` | | `ignore` | Leaves the prompt on screen | `UnhandledAlertException`, and every later command fails the same way | **`dismiss and notify` is the default**, and it is a defensible one: the browser is left usable for the next command, and the suite is still told that something unexpected happened. `ignore` is the value people reach for after misreading the name — it does not make dialogs harmless, it wedges the session until the test answers the prompt itself. ## Diagnosing a real failure - **Read `getAlertText()` off the exception.** After a dismiss-and-notify it is often the only surviving record of what the dialog said, so log it wherever failures are captured. - **Look at the line before the failing line.** The command that threw is the victim, not the cause; the trigger is the click, navigation or script call immediately before it. - **Ask whether the dialog belongs in the flow.** A confirm on **Place order** is product behaviour the test must answer; a `prompt` left behind by a debug script is a defect to remove. - **Check what the dismissal did to the application.** A dismissed confirm means the guarded action never happened, so later assertions fail for a second, derived reason. - **Do not reach for a longer timeout.** Nothing here is a timing problem: the command did not run out of time, it ran into a prompt. ## Handling it on purpose The stable fix is to expect the dialog wherever the product raises one: ```java driver.findElement(By.id("place-order")).click(); Alert confirm = driver.switchTo().alert(); String text = confirm.getText(); if (text.contains("Charge your card")) { confirm.accept(); } else { confirm.dismiss(); throw new AssertionError("Unexpected checkout dialog: " + text); } ``` Reading the text before answering is what turns the dialog from a hazard into an assertion: either the checkout confirms the right amount, or the test fails with a message naming the surprise. A non-default handler is a blunt instrument rather than a fix. `accept` applied to the whole session confirms every dialog unread, including one asking whether to discard the basket, and `dismiss` cancels every dialog unread, so the suite quietly stops exercising the paths behind them. Either is reasonable only for a dialog the suite genuinely does not care about and cannot avoid, and even then the trade is silence bought with coverage. Finally, remember `beforeunload`. Navigating away from a half-completed checkout form can raise a prompt that no click in the test triggered, and it reaches the same handler and produces the same `UnhandledAlertException` on whichever command runs next.

  • The dialog only appears on some runs of the checkout suite. Does that change how you handle it?
    No. Answer it explicitly whenever it can appear, and let the test decide what to do when it does not. An intermittent dialog usually means the trigger is data-dependent — a saved card, an out-of-stock title — so the honest fix is to control that data, not to soften the handler for the whole session.
  • What can you still learn about a dialog that dismiss and notify has already closed?
    The exception carries it: `UnhandledAlertException.getAlertText()` returns the message that was on screen, so logging that one string in the failure path usually identifies the dialog outright. Beyond that, the action on the line before the failing command tells you which step raised it.
  • When is setting a non-default prompt handler actually the right call?
    When a dialog is genuinely outside the suite's interest and cannot be avoided — a third-party widget's notice, say — and the suite's assertions do not depend on the path behind it. Even then prefer `dismiss` over `accept`, because accepting confirms destructive actions unread, and never use `ignore` as a quietening measure.

saying these in an interview costs you the question

  • Says the dialog vanished on its own or the browser closed it
  • Treats UnhandledAlertException as flakiness and adds a retry or a longer wait
  • Thinks switchTo().alert() threw the error rather than the next command
  • Sets the handler to accept everywhere so nothing fails, confirming dialogs unread
  • Believes ignore makes dialogs harmless instead of leaving them blocking