how to handle Stale Element Reference Exception in Python Selenium
A stale element reference exception is thrown in one of two cases:
The element that we are trying to interact
1. has been deleted entirely
2. no longer attached to the DOM
First cause is more common than the second one. We have reference to an element that has been deleted or changed in wep page after finding the reference and we are still trying to use the same reference, which is stale now, to interact with it.
Somethings to look for:
1. You might be trying to get any of element properties after clicking an element but clicking on the element opens a new page.
2. Page is being refreshed after finding element and before your interaction
3. Your previous action, after finding element but before interaction with element, made changes in part of or entire page.
Generally this is due to the DOM being updated and you trying to access an updated/new element with invalid/old reference.
A Sample Scenario:
find element using locator and assign it to a variable ‘x’
do some other operation that changes DOM
now try to interact with element ‘x’
We can get around this issue by adding some custom wrappers. Implement a wrapper in such a way that this will handle the StaleElementException within, then use the locator to re-evaluate and get the new WebElement object to interact with. This way we can keep the code that handles the exception in one class.
Sometimes the tiny time gap between when the WebDriver finds the element and when the WebDriver tries to interact with the element may cause stale element reference exception. Wrappers can be used here as well
Here in this html page, we are trying to type username and password. First step, we are finding reference to username and password text fields. Second step, we are entering username into username field. Third step, we are clicking on a link which reloads the entire page(This could happen with our knowledge or without our knowledge, Here we are doing it purpose fully). Fourth step, we are trying to enter password into password field with the reference that we found before page reload.
This is a condition where we get stale element reference exception – StaleElementReferenceException. Run the first python code sample to see the exception. In the second python code sample, we have handled exception using try-except
<html> <head> <title>AllSelenium.info</title> </head> <body> <h4>Page to test StaleElementReferenceException</h4> <p>Username: <input class="username" id="idUsername" type="text" name="username" /></p> <p>Password: <input class="password" id="idPassword" type="password" name="password" /></p> <select id="idCountryList" name="CountryList" class="select country list"> <option value="india">India</option> <option value="australia">Australia - AUZ</option> <option value="srilanka">Sri Lanka</option> <option value="england" selected>England</option> </select> <a id="reloadLink" href="#" onclick="location.reload()">Reload Page</a> </body> </html>
Note: Please save this html in a file before using it – StaleElementExceptionTest.html
Python code Sample that throws StaleElementReferenceException:
from selenium import webdriver chromeOptions = webdriver.ChromeOptions() chromeOptions.add_argument("--start-maximized") driver = webdriver.Chrome(chrome_options=chromeOptions, executable_path="path to chromedriver") driver.get("file:///data/StaleElementExceptionTest.html") # path to html file usernameElement = driver.find_element_by_id("idUsername") passwordElement = driver.find_element_by_id("idPassword") usernameElement.send_keys("testuser") driver.find_element_by_id("reloadLink").click() passwordElement.send_keys("password") driver.quit()
Python code Sample that throws and handles StaleElementReferenceException:
from selenium import webdriver from selenium.common.exceptions import StaleElementReferenceException chromeOptions = webdriver.ChromeOptions() chromeOptions.add_argument("--start-maximized") driver = webdriver.Chrome(chrome_options=chromeOptions, executable_path="path to chromedriver") driver.get("file:///data/StaleElementExceptionTest.html") # path to html file usernameElement = driver.find_element_by_id("idUsername") passwordElement = driver.find_element_by_id("idPassword") usernameElement.send_keys("testuser") driver.find_element_by_id("reloadLink").click() try: passwordElement.send_keys("password") except StaleElementReferenceException as Exception: print('StaleElementReferenceException while trying to type password, trying to find element again') passwordElement = driver.find_element_by_id("idPassword") passwordElement.send_keys("password") driver.quit()
In this way, inside StaleElementReferenceException catch block we are finding the password element again and trying to send password text value.
This is a good way to solve StaleElementReferenceException issue However this can happen to any element that we are trying to operate on and it is not good to do try/catching for all elements in the test script. Hence it is always better to check for conditions like this and either handle only elements requires this special handling or change the flow in such way that the StaleElementReferenceException scenarios are avoided.
Please let me know your thoughts about this famous stale element reference exception and any other ideas to handle this in comments.