Blog
StaleElementReferenceException in Selenium: Causes, Fixes and Code Examples

Adwitiya Pandey
Published on

Table of contents
Lorem ipsum
Lorem ipsum
Lorem ipsum
Lorem ipsum
Lorem ipsum
StaleElementReferenceException is one of the most common errors Selenium users run into, and one of the most frustrating. Your test finds an element, the page changes slightly, and the next click fails, even though the element still looks exactly the same on screen.
The usual fixes, such as re-locating elements, explicit waits, retries and page objects, all help. But they treat the symptom, not the cause. This guide explains why stale elements happen, shows each fix with working Java code, and explains how AI test platforms avoid the problem by identifying elements differently.
What is StaleElementReferenceException?
StaleElementReferenceException is thrown when Selenium tries to use a web element that’s no longer attached to the page’s DOM.
When you call findElement(), Selenium returns a reference to one specific node in the DOM. If that node is removed or replaced, for example because the page re-rendered, the reference points to something that no longer exists. Any action on it, such as clicking, typing or reading text, throws the exception.
The error message looks like this:
StaleElementReferenceException is a subclass of WebDriverException. It doesn’t mean your locator is wrong. It means the reference you’re holding is out of date, and you need to find the element again.
When Does a Selenium Stale Element Reference Exception Occurs?
Cause | What Happens | Common Example |
|---|---|---|
Page refresh or navigation | Every element reference from the old page is discarded | Clicking a link, then using an element found before the click |
JavaScript re-rendering | Frameworks destroy and recreate elements, even when nothing visible changes | React, Vue or Angular updating a component after state changes |
Element removed and recreated | A new element with identical attributes replaces the old one | A table refreshing its rows after sorting or filtering |
Switching frames or windows | The element belongs to a different browsing context | Using an element found inside an iframe after switching back to the main page |
AJAX updates | Part of the page is replaced without the URL changing | Search results, prices or live data updating in place |
Stale elements are especially common in single-page applications, ecommerce sites where baskets and prices update constantly, financial dashboards with live data, and healthcare systems with forms that change as you fill them in.
How to Fix StaleElementReferenceException in Selenium
Method 1: Re-Locate the Element Before Each Interaction
The simplest fix is to stop holding on to element references. Find the element again each time you use it.
Pros: simple, and removes stored references that can go stale
Cons: repetitive, and it doesn’t help if the DOM changes between finding and acting
Method 2: Use Explicit Waits
Wait for the element to be in the state you need before acting on it.
When you know the DOM is about to change, combine stalenessOf() and refreshed() to wait for the old element to disappear and the new one to be ready:
Pros: handles timing well, and is more reliable than implicit waits
Cons: needs waits throughout your suite, and the element can still go stale after the wait ends
Method 3: Retry the Action
Catch the exception and try again with a freshly located element.
Pros: handles brief re-renders, and is easy to reuse
Cons: adds time, and can hide real problems if retries become the default answer
Method 4: Use Page Objects with Lazy Loading
With Selenium’s PageFactory, fields annotated with @FindBy are proxies. Selenium finds the element each time you use the field, rather than once when the page object is created.
Avoid adding @CacheLookup to elements that re-render, because it stores the first reference and brings the stale element problem back.
Pros: tidier code, and elements are found when they’re used
Cons: an element can still go stale between being found and being used, and PageFactory takes some set-up
Method 5: Tell WebDriverWait to Ignore Stale Elements
You can tell a wait to keep trying when it hits a stale element.
Pros: combines waiting and stale element handling in one place
Cons: only protects the code inside the wait, and can hide genuine instability
Which Fix Should You Use?
Situation | Best Fix |
|---|---|
You store an element, then do something that changes the page | Re-locate the element before each use |
You know an action will refresh part of the page | Wait for staleness, then wait for the new element |
A component re-renders unpredictably for a moment | A short retry, or a wait that ignores stale elements |
You want cleaner code across a large suite | Page objects without |
Why These Fixes Only Go So Far
All of these methods work around the same limitation. Selenium identifies an element with one locator, holds a reference to one DOM node, and has no idea that a newly rendered button is the same “Save” button a user sees.
Explicit waits deal with timing, not with elements being replaced.
Retries hide the problem rather than preventing it.
Page objects organise code, but don’t make locators any less fragile.
Re-locating elements adds code without making identification smarter.
On a small, stable application, that’s manageable. On a fast-changing single-page app with hundreds of tests, handling stale elements becomes part of nearly every test you write, and part of most failures you investigate.
How Virtuoso QA Avoids Stale Elements
Virtuoso QA doesn’t hold on to element references between steps. Each step identifies its element at the moment it runs, using many signals together, such as visible text, label, role, position and surrounding context.
If the application re-renders a button, the next step simply finds the new one.
Plain English Instead of Stored References
Instead of finding, storing and re-finding elements in code, you describe the action:
There’s no element reference to go stale, and no wait or retry code to write.
To learn how plain English steps let more of your team build and maintain tests, read our guide to natural language programming in testing.
Identification from Many Signals
Because each element is identified from several attributes at once, a change to one of them, such as a regenerated ID or a new class name, doesn’t stop the step finding it.
Repairs Your Team Reviews
When a release changes the page more significantly, Virtuoso QA proposes a repair for your team to accept or reject. Tests keep running through UI changes, and every change leaves a record.
Also read: our guide to self-healing in continuous testing explains how reviewable repairs keep suites stable through frequent releases.
Live Authoring and Clear Failures
Each step runs against the live application as you write it, so you see immediately whether it works. When a run fails, you see the failed step beside the last passing run, with screenshots, the DOM snapshot, network data and a likely cause.
Bringing Selenium Suites Across
GENerator converts existing Selenium tests into plain English journeys, so you keep the coverage you’ve built and leave stale element handling behind. Explore GENerator to see how the conversion works.
Related Reads
StaleElementReferenceException FAQs
What causes StaleElementReferenceException in Selenium?
How do you handle stale element reference in Selenium WebDriver?
What is the difference between NoSuchElementException and StaleElementReferenceException?
Can I completely avoid StaleElementReferenceException in Selenium?
How does AI native testing prevent stale element exceptions?
How long does it take to migrate Selenium tests to AI native platforms?












