NullPointerException in Selenium
The Error
java.lang.NullPointerException:
Cannot invoke "org.openqa.selenium.WebElement.sendKeys(java.lang.CharSequence[])"
because "this.username" is null
Your locator is right and the element is on the page — yet something is null. A NullPointerException in Selenium almost never means the element wasn't found (that's NoSuchElementException). It means a Java variable — a WebElement field, the driver, or a returned value — was never given an object. Since Java 14, the message names the exact variable, so read the "because … is null" part first: it tells you which of the causes below you have.
Quick Diagnosis
| What's null | Likely cause | Fix |
|---|---|---|
A @FindBy field |
No PageFactory.initElements() |
Call it in the page constructor (Cause 1) |
driver in every test |
A local variable shadows the field | Assign the field (Cause 2) |
driver inside a page object |
Page created before the driver | Create the driver first (Cause 3) |
driver only in parallel runs |
ThreadLocal not set on this thread | Set it in @BeforeMethod (Cause 4) |
driver after a test finished |
Used after quit() / remove() |
Fix the lifecycle (Cause 5) |
A String from an attribute |
The attribute doesn't exist → null | Null-safe comparison (Cause 6) |
| A field set inside a condition | The branch never ran | Assign it on every path (Cause 7) |
Cause 1: Missing PageFactory.initElements() ⭐
@FindBy is only an annotation — metadata. It does nothing by itself. Something has to read it and fill the field, and that something is PageFactory.initElements(). Without it, every @FindBy field stays null.
@FindBy(id = "username")
private WebElement username; // null until initElements() runs
public class LoginPage {
private final WebDriver driver;
@FindBy(id = "username") private WebElement username;
@FindBy(id = "password") private WebElement password;
@FindBy(id = "login") private WebElement loginBtn;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this); // ⭐ the line that makes @FindBy work
}
public void login(String user, String pass) {
username.sendKeys(user);
password.sendKeys(pass);
loginBtn.click();
}
}
This is the most common cause. If a page class has a second constructor (or extends a base page), make sure every path calls initElements().
Cause 2: The Driver Field Is Shadowed
// ❌ Declares a NEW local variable — the field stays null
public class BaseTest {
protected WebDriver driver;
@BeforeMethod
public void setUp() {
WebDriver driver = new ChromeDriver(); // local variable, thrown away at the end of the method
}
}
// ✅ Assign the field
@BeforeMethod
public void setUp() {
driver = new ChromeDriver();
}
It compiles, the browser even opens — and every test then fails with driver null. (We ran the same pattern in plain Java: after the "setup" method, the field was still null.)
Cause 3: Page Object Created Before the Driver
// ❌ LoginPage receives null
LoginPage login = new LoginPage(driver);
driver = new ChromeDriver();
// ✅ Driver first, then pages
driver = new ChromeDriver();
LoginPage login = new LoginPage(driver);
Watch for page objects created as fields of a test class (LoginPage login = new LoginPage(driver); at class level) — those run when the test object is constructed, before @BeforeMethod has created the browser. Create pages inside the test or after setup.
Cause 4: ThreadLocal Driver Not Set on This Thread
private static final ThreadLocal<WebDriver> DRIVER = new ThreadLocal<>();
public static WebDriver getDriver() {
return DRIVER.get(); // null on any thread that never called set()
}
Each thread sees only its own value. If the driver is created in @BeforeSuite or @BeforeClass, tests running on other threads get null — which is why the NPE appears only in parallel runs. (Verified: a value set on the main thread reads as null from another thread.) Create the driver in @BeforeMethod, on the same thread as the test. More: Parallel Execution & Grid.
Cause 5: Using the Driver After quit() or remove()
A helper that runs after teardown — a listener taking a screenshot, a @AfterClass method, a retry — may find the driver already quit and removed from the ThreadLocal. Take screenshots before quit(), and guard teardown code:
WebDriver d = DriverFactory.get();
if (d != null) {
// screenshot, then quit
}
Cause 6: A Null Attribute or Value
findElement() never returns null — it throws NoSuchElementException. But attribute methods do return null when the attribute doesn't exist:
String cls = element.getDomAttribute("aria-invalid"); // null if the attribute isn't there
if (cls.equals("true")) { … } // 💥 NullPointerException
if ("true".equals(cls)) { … } // ✅ null-safe
if (Objects.equals(cls, "true")) { … } // ✅ null-safe
The same applies to values read from config files, JSON test data or a Map (map.get("missingKey") returns null). Put the known constant first, or use Objects.equals() / getOrDefault().
Cause 7: A Field Assigned Only Inside a Condition
private WebElement promoBanner; // a field — Java allows it to stay null
public void closeBannerIfShown() {
if (isPromoActive()) {
promoBanner = driver.findElement(By.id("promo"));
}
promoBanner.click(); // 💥 when the promotion isn't active
}
With a local variable, Java refuses to compile this ("variable might not have been initialized") — the NPE happens with fields, where Java assumes null is fine. Keep the action inside the branch, or check with findElements(...).isEmpty() first.
Prevent It: Plain By Locators
// PageFactory — needs initElements(); lazy proxies can also go stale
@FindBy(id = "username")
private WebElement username;
// Plain By locators — nothing to initialise, no NPE from missing init ⭐
private final By username = By.id("username");
public void enterUser(String u) {
driver.findElement(username).sendKeys(u);
}
Many modern frameworks prefer By fields with explicit-wait helpers: there's nothing to initialize, and each call finds a fresh element, which also avoids StaleElementReferenceException. PageFactory is still valid — just remember initElements().
See how elements are located and used step by step in the Selenium WebDriver Visualizer.
The Interview Answer
"A NullPointerException in Selenium means a Java reference was never assigned — it's not an element-not-found error. The most common cause in Page Object frameworks is forgetting PageFactory.initElements, because @FindBy is only an annotation. Other causes are a shadowed driver variable in setup, creating page objects before the driver, a ThreadLocal driver that wasn't set on the current thread in parallel runs, and null attribute values. I read the 'because … is null' part of the message to find which one it is. In my framework we use By locators, so there's nothing to initialize."
From Real Projects
My Selenium work — Java, TestNG and a POM-based hybrid framework on Canolog and Testsigma — involved running the same scripts in batch, group, parallel and cross-browser mode on Chrome and Firefox. That's where problems like the one on this page tend to surface: a script that passes alone can fail when timing, browser or execution order changes. Keeping locators in POM classes meant each fix happened in one place, and reviewing scripts before they joined the suite caught many issues early. Check that the page class was initialized before any of its elements were used.
📚 Official documentation: Selenium documentation
FAQs
Why is my @FindBy element null?
Because @FindBy is only metadata. Call PageFactory.initElements(driver, this) in the page constructor.
Where should initElements() go?
In the page object's constructor, right after assigning the driver.
Why is my driver null even though the browser opened?
Usually a shadowed variable: WebDriver driver = new ChromeDriver(); inside setup creates a local copy and leaves the field null.
Why does the NPE happen only in parallel runs?
A ThreadLocal driver returns null on threads where set() was never called. Create the driver per test method.
Can findElement() return null?
No — it throws NoSuchElementException. Nulls come from uninitialised fields, the driver, or methods like getDomAttribute().
How do I avoid it entirely?
Use By locators instead of @FindBy fields, create the driver in @BeforeMethod, and use null-safe comparisons.