Random "Element is no longer attached to the DOM" StaleElementReferenceException Random "Element is no longer attached to the DOM" StaleElementReferenceException java java

Random "Element is no longer attached to the DOM" StaleElementReferenceException


Yes, if you're having problems with StaleElementReferenceExceptions it's because there is a race condition. Consider the following scenario:

WebElement element = driver.findElement(By.id("foo"));// DOM changes - page is refreshed, or element is removed and re-addedelement.click();

Now at the point where you're clicking the element, the element reference is no longer valid. It's close to impossible for WebDriver to make a good guess about all the cases where this might happen - so it throws up its hands and gives control to you, who as the test/app author should know exactly what may or may not happen. What you want to do is explicitly wait until the DOM is in a state where you know things won't change. For example, using a WebDriverWait to wait for a specific element to exist:

// times out after 5 secondsWebDriverWait wait = new WebDriverWait(driver, 5);    // while the following loop runs, the DOM changes - // page is refreshed, or element is removed and re-addedwait.until(presenceOfElementLocated(By.id("container-element")));        // now we're good - let's click the elementdriver.findElement(By.id("foo")).click();

The presenceOfElementLocated() method would look something like this:

private static Function<WebDriver,WebElement> presenceOfElementLocated(final By locator) {    return new Function<WebDriver, WebElement>() {        @Override        public WebElement apply(WebDriver driver) {            return driver.findElement(locator);        }    };}

You're quite right about the current Chrome driver being quite unstable, and you'll be happy to hear that the Selenium trunk has a rewritten Chrome driver, where most of the implementation was done by the Chromium developers as part of their tree.

PS. Alternatively, instead of waiting explicitly like in the example above, you can enable implicit waits - this way WebDriver will always loop up until the specified timeout waiting for the element to become present:

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS)

In my experience though, explicitly waiting is always more reliable.


I have been able to use a method like this with some success:

WebElement getStaleElemById(String id) {    try {        return driver.findElement(By.id(id));    } catch (StaleElementReferenceException e) {        System.out.println("Attempting to recover from StaleElementReferenceException ...");        return getStaleElemById(id);    }}

Yes, it just keeps polling the element until it's no longer considered stale (fresh?). Doesn't really get to the root of the problem, but I've found that the WebDriver can be rather picky about throwing this exception -- sometimes I get it, and sometimes I don't. Or it could be that the DOM really is changing.

So I don't quite agree with the answer above that this necessarily indicates a poorly-written test. I've got it on fresh pages which I have not interacted with in any way. I think there is some flakiness in either how the DOM is represented, or in what WebDriver considers to be stale.


I get this error sometimes when AJAX updates are midway. Capybara appears to be pretty smart about waiting for DOM changes (see Why wait_until was removed from Capybara), but the default wait time of 2 seconds was simply not enough in my case. Changed in _spec_helper.rb_ with e.g.

Capybara.default_max_wait_time = 5