What is StaleElementReferenceException and how do you fix it?
60-second answer
StaleElementReferenceException means the WebElement I'm holding no longer refers to an element in the current DOM, usually because the page refreshed, the element was re-rendered by JavaScript, or I navigated away and back. The reference is old, even if an identical element is now visible. The fix is to find the element again right before using it instead of storing it for a long time, wait for the refresh to finish with an explicit wait, or use a small retry for known re-rendering components.
Explanation
Common causes:
- AJAX updates a list or table and rebuilds the rows.
- React/Angular re-renders a component after state change.
- Page navigation or refresh.
Fixes:
- Store
Bylocators, notWebElements, and locate just before acting. - Wait for staleness of the old element:
ExpectedConditions.stalenessOf(oldElement), then re-find. - Use
ExpectedConditions.refreshed(...). - Retry once or twice for genuinely dynamic widgets (not a cover for bad design).
PageFactory proxies re-find on each call, but cached @CacheLookup elements can go stale.
Example
After applying a filter, the product grid reloads. Code that saved List<WebElement> products before filtering throws stale exceptions when reading their text.
Sample code
WebElement firstRow = driver.findElement(By.cssSelector("table tr"));
driver.findElement(By.id("apply-filter")).click();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.stalenessOf(firstRow)); // old DOM gone
List<WebElement> rows = driver.findElements(By.cssSelector("table tr")); // fresh