16

In my C# app to use selenium web driver I get this error:

OpenQA.Selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document

in this code:

IWebElement e = driver.FindElement(By.XPath(link_click), 10);
e.Click();

the error line is in the e.Click() but this is a procedure that executed successfully in same link specified by XPath before but failed on the last try! so what this error mean and how to fix it ?

zac
  • 4,495
  • 15
  • 62
  • 127
  • One way to prevent this, is to have a `WaitForPageToLoad` method that gets called when a page object opens. Then you can wait for one or two things on the page that indicate that it's ready, and then you can proceed with confidence that nothing will go stale underneath you. – mrfreester Apr 21 '17 at 16:38

3 Answers3

23

It means that either the element changed in the page, or element gets deleted, full reference in this link http://www.seleniumhq.org/exceptions/stale_element_reference.jsp

One way to cope with this, you could put retry, probably something like

bool staleElement = true; 
while(staleElement){
  try{
     driver.FindElement(By.XPath(link_click), 10).Click();
     staleElement = false;

  } catch(StaleElementReferenceException e){
    staleElement = true;
  }
}
adee alamsz
  • 393
  • 2
  • 6
  • 7
    this is risky, there is a real possibiility it may go in an infinite loop if iterations are unchecked. – Jayesh Doolani Apr 21 '17 at 14:29
  • 2
    yeah, but its only if the exception type StaleElementReferenceException which was the issue. Other exceptions will still be thrown and out of the loop For completeness of the solution, you could add checking timeout if(currentTime > start + timeout) break / throw exception so the test could be stopped when necessary – adee alamsz Apr 21 '17 at 14:35
  • 3
    Since you're explicitly catching StaleElement, I'm not sure how this would be looped forever. Seems like a safe workaround, unless of course the page is ridiculous and causes the element to go stale over and over forever, in which case you have bigger problems. – mrfreester Apr 21 '17 at 16:34
  • Once the element is stale, it won't ever become "unstale". Looping and retrying won't help. You have to avoid it in the first place. – JeffC Apr 22 '17 at 04:34
  • 2
    @JeffC, not necessarily true, in this case, by retrying finding the element, you try to get the new element, so it would not stale – adee alamsz Apr 22 '17 at 04:37
  • 1
    @JeffC, yep, if you retry only clicking, then yes, it won't help, but retrying finding element together with clicking will help. – Grengas May 08 '18 at 12:50
  • That's actually a great solution. I do agree that nodes do become "unstale" at some point. Perhaps, what, some javascript is running on page load and some object unstales after the Javascript has run? – Patrice Gagnon Nov 04 '19 at 16:14
  • 1
    you can of course define maximum retrial times and break the loop once retrial times reached. This solution should have provided a clear way to solve the problem. – Capitaine Jul 19 '20 at 16:29
1

I'd the same problem when i was doing date picker, with one of the site. I'd to get all the active (or enabled) buttons from the date picker and click each of that. When I iterated the elements it was getting stale. I'd re reiterate keeping another list. This may have happened because once the List gets selenium does not refer it back. Below is the fixed code

@Test
public void datePickerTest() throws InterruptedException{
    driver.get(baseURL);
    // click on flights tab 
    genericMethod.getElement("tab-flight-tab-hp", "id").click();

    // click departing date, such that the date picker is loaded  in the dom 
    genericMethod.getElement("flight-departing-hp-flight", "id").click(); 
    Thread.sleep(700);

    // pass the collected xpath where you can find all the dates which are enabled 
    String xpath=".//*[@id='flight-departing-wrapper-hp-flight']/div/div/div[2]/table/tbody/tr/td/button[not(@disabled)]";
    List<WebElement> activeDatesWebElement = genericMethod.getElements("xpath", xpath); 

    System.out.println("Number of Active Dates " + activeDatesWebElement.size());

    // work around for an element when it is found stale 
    List<String> activeDateListAsString = new ArrayList<String>();

    for(WebElement temp : activeDatesWebElement){
        activeDateListAsString.add(temp.getText());
    }


    // iterate all element in the list received, which is kept in list 
    for(String temp : activeDateListAsString){
        genericMethod.getElement("flight-departing-hp-flight", "id").click();

        Thread.sleep(500);


        String selectDateXpath=".//*[@id='flight-departing-wrapper-hp-flight']"
                + "/div/div/div[2]/table/tbody/tr/td/button[text()='"
                +temp+"']";

        genericMethod.getElement(selectDateXpath, "xpath").click(); 
        Thread.sleep(500);

    }

}
Naveen
  • 491
  • 5
  • 6
0

You get this error if element is not present while loading page. You need to wait until element is ready:

public static Func<IWebDriver, IWebElement> Condition(By locator)
{
    return (driver) => {
        var element = driver.FindElements(locator).FirstOrDefault();
        return element != null && element.Displayed && element.Enabled ? element : null;
    };
}

var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
var elementU = wait.Until(Condition(By.Name("j_username")));
elementU.Click();
ozanmut
  • 2,898
  • 26
  • 22