skip to content

In Selenium, can driver.findElement return null when nothing matches, or does it throw?

level: juniorimportance: nice to knowfreq 44%

answer

  1. How an API can report nothing found
  2. There is no null to check for
  3. The singular call objects instead of returning
  4. An unchecked exception, not a return value
  5. NoSuchElementException versus an empty list

basics

~10 s

It never returns null. Selenium's findElement throws NoSuchElementException when nothing matches, so a null check after it is unreachable code, while the plural findElements returns an empty list instead of throwing.

solid answer

~40 s

`findElement` is declared on Selenium's `SearchContext` interface as returning the first matching element or throwing `NoSuchElementException`; `null` is not part of the contract, so `if (element != null)` after a lookup is unreachable code. The exception is unchecked — `NoSuchElementException` extends `NotFoundException`, then `WebDriverException`, then `RuntimeException` — and it is the client's translation of the protocol's `no such element` error, returned with HTTP 404. The plural `findElements` takes the opposite approach: it returns a list of every match, or an empty list when nothing matches, and never throws for absence. So on a food-safety inspection form, use `driver.findElement` when the element must exist for the test to go on, and `driver.findElements(...).isEmpty()` when whether it exists is the actual question.

go deeper

for a junior

Be ready to say that the singular lookup throws and never returns null, and that the plural one returns an empty list. Interviewers use this to check you have actually run a test.

for a middle

Explain the exception hierarchy and the protocol error behind it, and why presence checks belong on the plural call rather than on a try/catch block.

for a senior

Point out where the distinction bites in a suite: absence checks built from caught exceptions swallow more than they mean to, and null checks after lookups mislead the next reader.

for a principal

Own the convention. Decide which of the two calls a suite reaches for by default, so that lookups fail loudly where an element is required and quietly where its presence is the question.

## Two calls, two ways of saying "nothing here" Selenium's element lookups live on the `SearchContext` interface, which both the driver and an individual element implement. It declares exactly two methods, and they disagree about how to report absence: - `WebElement findElement(By by)` returns **the first matching element**, and throws `NoSuchElementException` if nothing matches. It has no null-return case at all. - `List<WebElement> findElements(By by)` returns **a list of all matching elements, or an empty list if nothing matches**. It does not throw for an empty result. So on a food-safety inspection form, `driver.findElement(By.id("critical-violation-banner"))` either hands you the banner or raises an exception, while `driver.findElements(By.id("critical-violation-banner"))` hands you a list whose size is one or zero. ## What the exception actually is `org.openqa.selenium.NoSuchElementException` extends `NotFoundException`, which extends `WebDriverException`, which extends `RuntimeException`. Three consequences follow: - It is **unchecked**. The compiler does not force a `try`/`catch`, so a mistyped locator surfaces at run time, on the line of the lookup, as a failed test rather than a compile error. - It carries the locator, so the failure output usually tells you what was searched for without extra work. - It is **not** `java.util.NoSuchElementException`. The names are identical and both are unchecked, so an IDE can import the wrong one and a `catch` block will then silently never match. If a catch around a Selenium lookup seems to be ignored, check the import first. Underneath, the client is translating a protocol error. The remote end answers the W3C **Find Element** command with HTTP 404 and a body shaped like this: ```json { "value": { "error": "no such element", "message": "Unable to locate element: #critical-violation-banner", "stacktrace": "" } } ``` The `error` field is the error code the specification defines for "an element could not be located on the page using the given search parameters", and the client maps that code onto the exception class. ## Why a null check after findElement is dead code ```java WebElement banner = driver.findElement(By.id("critical-violation-banner")); if (banner != null) { // never false banner.click(); } ``` The comparison can never evaluate to `false`. If the banner is missing, the previous line has already thrown and the `if` is not reached; if it is present, a real element reference came back. The habit comes from APIs that use `null` to mean "absent", and it makes the code look defensive while defending nothing. Worse, it hides the intent: a reader thinks the test tolerates a missing banner, when it actually aborts. ## Which call to use for which question | Question | Call | Result when present | Result when absent | |---|---|---|---| | Give me the element | `findElement` | the first match | throws `NoSuchElementException` | | Give me all of them | `findElements` | a non-empty list | an empty list | | Is it there at all? | `findElements(...).isEmpty()` | `false` | `true` | | Is it missing? | `findElements(...).isEmpty()` | `false` | `true` | The pattern to take away is simple: **use the singular call when the element must exist for the test to continue, and the plural call when its existence is the thing you are asking about.** The plural call answers presence questions without exceptions and without control flow built out of `try`/`catch`. ## Where the same contract applies - **On the driver and on an element.** `WebDriver` and `WebElement` both implement `SearchContext`, so a lookup scoped to one violation row throws or returns an empty list on exactly the same terms as a document-wide one. - **Across every locator type.** `By.id`, `By.cssSelector`, `By.xpath` and the rest change how matching is done, not how absence is reported. - **Regardless of why nothing matched.** A removed element, a renamed class and a typo in the locator all produce the identical outcome, so the result tells you *that* nothing matched and never *why*. - **In every binding.** The names differ — the plural call is `find_elements` in Python and `FindElements` in C# — but the singular-throws, plural-returns-empty split is the same contract everywhere. ## The everyday shape in a test 1. To act on something, call `findElement` and let it throw. A missing element is a real failure, and the exception names the locator. 2. To branch on something, call `findElements` and check `isEmpty()` or `size()`. No exception is involved, so the branch reads as a value check. 3. Never write `== null` after either call. The singular one throws instead of returning `null`; the plural one returns an empty list, which is also never `null`. Both calls behave the same way whether they are issued against the driver or against an element, because both implement the same `SearchContext` contract — a lookup scoped to a row on the inspection form throws or returns an empty list on exactly the same terms as a document-wide one.

  • What does findElements return when the page has no match at all?
    An empty list. The `SearchContext` contract documents it as all matching elements or an empty list if nothing matches, and it is never `null` and never an exception. That is why presence and absence checks are written against the plural call: an empty result is a value you can test rather than a failure you have to catch.
  • Is NoSuchElementException checked or unchecked, and why does that matter?
    Unchecked: it descends from `WebDriverException`, which extends `RuntimeException`. Nothing forces you to handle it, so a missing element ends the test at the line of the lookup with the locator in the message — usually what you want. It also means a stray `catch` written against `java.util.NoSuchElementException` will never match Selenium's.

saying these in an interview costs you the question

  • Wraps findElement in a null check that can never be true
  • Thinks findElements throws when the page has no matching element
  • Says NoSuchElementException is checked and must be declared or caught
  • Believes findElement returns an empty WebElement when nothing matches
  • Confuses Selenium's NoSuchElementException with the java.util class of the same name