Skip to content
Selenium WebDriver · error message

Selenium: StaleElementReferenceException: stale element reference

RetryableStale elements

Last verified

The exact message
selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: stale element not found in the current frame; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#staleelementreferenceexception

What it means

A WebElement is a reference to one specific node in the page. This exception means the node your reference points to is no longer available: it was removed from the DOM, the page reloaded or navigated, or you switched to a different frame or window. Selenium cannot act on it, even if an identical-looking element is now on the page.

The wording depends on the driver version. Current ChromeDriver says stale element not found in the current frame or stale element not found; older versions said element is not attached to the page document. Firefox uses its own wording. All of them map to the W3C stale element reference error and the same exception class.

What is not wrong: your locator. Finding the element again with the same locator usually works immediately. The problem is reusing an old reference across a change.

What it looks like

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
old_row = driver.find_element(By.CSS_SELECTOR, "table tbody tr")
driver.find_element(By.ID, "refresh").click()
wait.until(EC.staleness_of(old_row))          # old table is gone
rows = wait.until(EC.presence_of_all_elements_located(
    (By.CSS_SELECTOR, "table tbody tr")))

Why it happens

  • The page re-rendered the element after you found it, common with React, Angular and Vue apps after data loads.
  • A navigation or refresh happened between find_element and the action.
  • You looped over a list of elements and a click inside the loop changed or reloaded the list.
  • You switched into an iframe or another window; references from the previous context are not reachable there (the 'in the current frame' variant).

How to fix it

  1. Find the element again right before using it instead of storing it earlier in the flow.
  2. Use an explicit wait that re-locates: WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, 'save'))).
  3. When iterating, collect stable data (text, href, IDs) first and re-find each element by that data inside the loop.
  4. Switch back to the right context (driver.switch_to.default_content() or the correct frame) before re-finding.
  5. For a known re-render, wait for the old element to go stale with EC.staleness_of(old) and then locate the new one.

How to stop it recurring

Keep element references short-lived: locate, act, and let go. Wrap common interactions in helpers that take a locator rather than a WebElement, so every call finds a fresh reference. After any action that triggers a reload or re-render, wait for a signal that the new content is ready before touching it.

Official documentation: www.selenium.dev/documentation/webdriver/troubleshooting/errors/#staleelementreferenceexception. See all Selenium error messages.

Related errors

Definitions

Quick answers

What does "StaleElementReferenceException: stale element reference" mean in Selenium?

A WebElement is a reference to one specific node in the page. This exception means the node your reference points to is no longer available: it was removed from the DOM, the page reloaded or navigated, or you switched to a different frame or window. Selenium cannot act on it, even if an identical-looking element is now on the page. The wording depends on the driver version.

How do I fix "StaleElementReferenceException: stale element reference"?

1. Find the element again right before using it instead of storing it earlier in the flow. 2. Use an explicit wait that re-locates: WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, 'save'))). 3. When iterating, collect stable data (text, href, IDs) first and re-find each element by that data inside the loop. 4. Switch back to the right context (driver.switch_to.default_content() or the correct frame) before re-finding. 5. For a known re-render, wait for the old element to go stale with EC.staleness_of(old) and then locate the new one.

Run browser automation you can watch and take over

Autonoly runs each job in a real cloud Chromium browser driven by Playwright. Timeouts and detached elements still happen; the difference is that you can watch the run live, see the step that failed, and take control of the browser to finish it.

Also see Live browser control.