StaleElementReferenceException on Python Selenium StaleElementReferenceException on Python Selenium python python

StaleElementReferenceException on Python Selenium


It means the element is no longer in the DOM, or it changed.

The following code will help you find the element by controlling and ignoring StaleElementExceptions and handling them just like any other NoSuchElementException. It waits for the element to NOT be stale, just like it waits for the element to be present. It also serves as a good example on how to properly wait for conditions in Selenium.

from selenium.common.exceptions import NoSuchElementExceptionfrom selenium.common.exceptions import StaleElementReferenceExceptionfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditionsmy_element_id = 'something123'ignored_exceptions=(NoSuchElementException,StaleElementReferenceException,)your_element = WebDriverWait(your_driver, some_timeout,ignored_exceptions=ignored_exceptions)\                        .until(expected_conditions.presence_of_element_located((By.ID, my_element_id)))

To better understand the problem, imagine you are inside a for loop and think what happens during the iterations:

  1. something changes when you click on the element (last line)
  2. So the page is changing
  3. You enter the next iteration. Now are trying to find a new element (your first line inside the loop).
  4. You found the element
  5. It finishes changing
  6. You try to use it by getting an attribute
  7. Bam! The element is old. You got it in step 4, but it finished changing on step 5


Selenium Support Explicit and Implicit Waits. If you think waiting for certain amount of time is enough for your page to be loaded, use:

driver.implicitly_wait(secs)

but if you want to wait for a special event (e.g. waiting for a particular element to be loaded) you can do something like:

from selenium.webdriver.support.ui import WebDriverWait......def find(driver):    element = driver.find_elements_by_id("data")    if element:        return element    else:        return Falseelement = WebDriverWait(driver, secs).until(find)


Beyond the answers here, if you are using ActionChains, and the page has changed, be sure to reinstantiate your ActionChains object (dont reuse an old one), otherwise your ActionChain will be using a stale DOM. I.e. do this;

action_chain = ActionChains(driver)     action_chain.double_click(driver.find_element_by_xpath("//tr[2]/p")).perform()

Or better yet dont use an instantiation;

ActionChains(driver).double_click(driver.find_element_by_xpath("//tr[2]/p")).perform()