When I call the below statement:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, tag))).click()
I was periodically getting a StaleElementReferenceException
, which I thought shouldn't happen considering the explicit wait I've used.
I had to use the below code fixed the issue but I don't understand why the above can ever raise StaleElementReferenceException
in the 1st place.
def click_element_with_retry(driver, tag, seconds):
# for some reason the element_to_be_clickable by itself is not working, and periodically retruns a StaleElementReferenceException
end_time = datetime.now() + timedelta(seconds=seconds)
while datetime.now() < end_time:
try:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, tag))).click()
break
except TimeoutException:
raise_vba_error_message_and_quit(driver, f"Mars Web element could not be found after timeout", "Timeout Error")
except StaleElementReferenceException:
continue
Any suggested reading or thoughts why this might be happening? I'm using a edge driver if that matters
When I call the below statement:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, tag))).click()
I was periodically getting a StaleElementReferenceException
, which I thought shouldn't happen considering the explicit wait I've used.
I had to use the below code fixed the issue but I don't understand why the above can ever raise StaleElementReferenceException
in the 1st place.
def click_element_with_retry(driver, tag, seconds):
# for some reason the element_to_be_clickable by itself is not working, and periodically retruns a StaleElementReferenceException
end_time = datetime.now() + timedelta(seconds=seconds)
while datetime.now() < end_time:
try:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, tag))).click()
break
except TimeoutException:
raise_vba_error_message_and_quit(driver, f"Mars Web element could not be found after timeout", "Timeout Error")
except StaleElementReferenceException:
continue
Any suggested reading or thoughts why this might be happening? I'm using a edge driver if that matters
Share Improve this question edited Mar 11 at 12:56 Guy 51.1k10 gold badges48 silver badges94 bronze badges asked Mar 11 at 12:37 PaMcDPaMcD 11715 bronze badges 3- always put full error message because there are other useful information. – furas Commented Mar 11 at 17:25
- Selenium may keep reference to items in browser memory (instead of Python objects). If you click something then browser may move element in memory and references may be incorrect. After click you may have to search element(s) again to get correct references to object in memory. – furas Commented Mar 11 at 17:28
- WebDriverWait's polling loop only ignores not found exceptions. Any methods called by the element reference can throw an exception. (Most common would be Stale Element, or Click Intercepted exceptions) In this case the Expected Condition is running some methods of the element reference to see if it's clickable. If the DOM is updated between the time it's found and when one of its methods is run, you'll get a stale element. (meaning it was found, but the element reference is no longer valid) In this case the DOM is probably in the process of updating when you find the element. – browsermator Commented Mar 11 at 18:41
1 Answer
Reset to default 1Have a look at the implementation
def element_to_be_clickable(
mark: Union[WebElement, Tuple[str, str]]
) -> Callable[[WebDriverOrWebElement], Union[Literal[False], WebElement]]:
"""An Expectation for checking an element is visible and enabled such that
you can click it.
element is either a locator (text) or an WebElement
"""
# renamed argument to 'mark', to indicate that both locator
# and WebElement args are valid
def _predicate(driver: WebDriverOrWebElement):
target = mark
if not isinstance(target, WebElement): # if given locator instead of WebElement
target = driver.find_element(*target) # grab element at locator
element = visibility_of(target)(driver)
if element and element.is_enabled():
return element
return False
return _predicate
The WebElement
that is sent to the function (or located in it) calls the functions is_displayed()
and is_enabled()
(or click()
afterwards). Each one of them can cause StaleElementReferenceException
if the element reference is lost in the time between the locating and checking.