Your test fails and the message is almost empty:
selenium.common.exceptions.TimeoutException: Message:
No element name. No line of explanation. Just a timeout.
The instinct is to raise the number and move on. Resist it. A TimeoutException does not mean the page was slow. It means the condition you waited for never became true. Those are different problems, and only one of them is fixed by waiting longer.
What the error actually says
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("toast")));
Read that as a question: "is an element with id toast visible yet?" Selenium asks it repeatedly, roughly twice a second, for ten seconds. If the answer is still no at the end, you get a TimeoutException.
So the error tells you one thing: that question never got a yes. Your job is to work out which part of the question was wrong.
There are five real reasons. In rough order of how often they turn out to be the cause.
Cause 1: The locator is wrong
This is the most common by a distance, and it is the one people check last.
If the selector does not match anything, the condition can never be true, and you will wait the full ten seconds to be told nothing. The timeout is a symptom. The locator is the bug.
How to tell. Open the page yourself, open devtools, and run the selector in the console:
document.querySelectorAll('[data-testid="toast"]') // CSS
$x('//div[@class="toast"]') // XPath, Chrome devtools
Empty result means you found your problem, and no timeout value will fix it.
Watch for the usual causes: a class that changed with a redesign, a typo, a dynamic id like input-4f3a that is different on every load, or a selector copied from "Copy XPath" that encodes the whole page structure.
This overlaps heavily with NoSuchElementException. The difference is only which call you made. findElement throws NoSuchElement immediately. wait.until keeps asking and eventually throws TimeoutException.
Cause 2: You waited for the wrong condition
The element is there. The condition you chose is not the one you meant.
presenceOfElementLocated only asks whether the element is in the DOM. An element can be in the DOM and invisible, behind an overlay, or disabled. So this passes and the next line fails:
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("submit")));
driver.findElement(By.id("submit")).click(); // ElementNotInteractableException
The reverse is just as common. You wait for visibility on an element that is deliberately hidden until later, and time out even though the app is behaving correctly.
Pick the condition that matches what you are about to do:
| You are about to... | Wait for |
|---|---|
| Read text or an attribute | presenceOfElementLocated |
| See it on screen | visibilityOfElementLocated |
| Click it | elementToBeClickable |
| Check it went away | invisibilityOfElementLocated |
| Check the text changed | textToBePresentInElement |
| Confirm navigation | urlContains or titleIs |
If a click still fails after elementToBeClickable, something is covering it. That is ElementClickIntercepted.
Cause 3: You are looking in the wrong document
The element is on the screen. Selenium genuinely cannot see it.
Two situations cause this, and both are invisible in a screenshot:
It is inside an iframe. An iframe is a separate document. Until you switch into it, Selenium is searching the outer page:
driver.switchTo().frame(driver.findElement(By.cssSelector("iframe#payment")));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("card-number")));
driver.switchTo().defaultContent(); // remember to come back out
Handling iframes covers this properly.
It is in a new tab or window. Selenium stays on the tab it started on until you tell it otherwise:
for (String handle : driver.getWindowHandles()) {
driver.switchTo().window(handle);
}
If a timeout appears right after a click that opened something, check this before anything else.
Cause 4: The application really is slow, or broken
Sometimes the boring answer is right. The request took twelve seconds, or it failed and the element genuinely never arrived.
How to tell the difference, and this is the step most people skip: open the browser's network tab and console on the page under test.
- A pending request that never resolves means a backend problem, not a test problem.
- A 500 response means you found a real bug. Your test did its job.
- A JavaScript error in the console can stop rendering entirely, so the element never appears.
This is the case where raising the timeout is legitimate, and even then only after you have confirmed the request completes and the app is healthy.
Cause 5: Implicit and explicit waits are fighting
This one is genuinely confusing, because the timeout you get is not the timeout you set.
If you have set an implicit wait and you use WebDriverWait, both are polling. The implicit wait makes every internal findElement call inside the explicit wait block for its own duration. The two compound, and you get waits far longer than either number, in ways that differ by driver version.
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); // do not mix
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
Pick one strategy. Use explicit waits, and set the implicit wait to zero. Explicit waits can express every condition in the table above. Implicit waits can only ask whether an element exists.
How to debug one in five minutes
- Run the selector in the browser console. If it matches nothing, stop. You have found it.
- Check the condition matches the action. Are you about to click something you only waited to exist?
- Ask whether it is in a frame or another tab. A click just before the failure is the clue.
- Open the network tab and console. Confirm the app is healthy before blaming the test.
- Only then, consider the duration. And if you raise it, write down why.
Make the failure tell you something
The default message is empty, which is why this error wastes so much time. Give it a message:
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.withMessage("Toast never became visible after saving the contact");
WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.ID, "toast")),
"Toast never became visible after saving the contact",
)
Six months from now, on a build server, at the end of a Friday, that sentence is worth more than the stack trace. I have lost an hour to a bare TimeoutException in a suite of two hundred tests, and the fix afterwards took four minutes.
What not to do
Do not just raise the number. If ten seconds was not enough and thirty is, you have not fixed anything. You have made the failure rarer and the suite slower, and it will come back on a busy build agent.
Do not replace it with a sleep.
Thread.sleep(5000); // no
A sleep waits the full time even when the page is ready, and still fails when it is slower than your guess. It is the single biggest cause of slow, flaky Selenium suites. Fixing flaky tests goes through why.
Do not catch and ignore it. A swallowed TimeoutException turns a failing test into a passing one that checks nothing. That is worse than no test, because it reports safety you do not have.
Quick reference
| Symptom | Likely cause | First check |
|---|---|---|
| Times out every run, on every machine | Wrong locator | Run the selector in devtools |
| Wait passes, next line throws | Wrong condition | Match the condition to the action |
| Times out right after a click | New tab or iframe | Check window handles and frames |
| Only fails in CI | Slow environment or viewport | Network tab, and set the window size |
| Waits far longer than the number you set | Mixed implicit and explicit | Set implicit to zero |
| Fails randomly, passes on retry | Race condition | Wait for the condition, not a duration |
Remember this
TimeoutException means your condition never came true. It is a message about the question you asked, not about how fast the page was.
Check the locator first, because it is wrong more often than anything else. Match the condition to the action you are about to take. Never mix implicit and explicit waits. And always give the wait a message, so the next failure explains itself.
The official reference is the Selenium waits documentation.