Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

When Selenium raises StaleElementReferenceException, the WebElement you previously found no longer points to a usable element in the current page context. Keep the locator, wait for the page state you actually need, then locate the element again immediately before using it. If an update is expected to remove the old node, wait for EC.staleness_of(old_element) before finding its replacement.

What the exception means

Selenium identifies an element with a reference to a particular DOM node. That reference becomes stale when Selenium can no longer access the node in the current DOM. A variable holding the old WebElement does not automatically update to point to a replacement.

The exception can follow navigation or a page refresh, a JavaScript update that removes and recreates a node, or a change to an iframe context. A delay may hide a timing issue, but it does not repair an invalid reference. First establish whether the page or frame changed; then find the element in the correct context again. See Selenium’s stale-element troubleshooting guidance and its Python exception documentation for Selenium 4.49.0.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

First check the page and browsing context

Before retrying, confirm that the browser is on the expected page and, if the target is inside a frame, that Selenium has switched into the frame currently containing it. A reference found before navigation, refresh, or a frame change may no longer apply. Fixing the context comes before waiting for the element.

  • After navigation or refresh, wait for a meaningful condition on the destination page and locate the target again.
  • After a dynamic update, determine whether the target node was replaced or merely became hidden or disabled.
  • For an iframe, switch to the intended current frame before locating the element inside it.

Use a locator-based explicit wait

Store the locator rather than carrying a WebElement across page updates. A locator-based expected condition can find the current matching element as the wait polls. The following Python example waits until a button is visible and enabled before clicking it:

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

submit_locator = (By.ID, "submit")
submit = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable(submit_locator)
)
submit.click()

element_to_be_clickable checks that the located element is visible and enabled. If you need only to confirm that an element exists in the DOM, use presence_of_element_located; for an element that must be visible, use visibility_of_element_located. Choose the condition that represents the state your next action requires rather than adding a fixed sleep. Selenium documents these Python conditions in Waiting with Expected Conditions.

A wait checks its condition when it polls; the page can still change after the condition succeeds. Keep the locate-and-act sequence close together. If the application can replace the target in that interval, handle that specific transition instead of assuming the wait eliminates every race.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Wait for the old element to go stale when replacement is expected

If a known action replaces a row, card, or other node, waiting for the old element to become detached can make the transition explicit. Then locate the replacement with the original locator:

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

row_locator = (By.CSS_SELECTOR, "tr.selected")
old_row = driver.find_element(*row_locator)

# Trigger the action that replaces the row here.
WebDriverWait(driver, 10).until(EC.staleness_of(old_row))

new_row = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located(row_locator)
)

staleness_of waits until the old reference is no longer attached to the DOM. It does not revive that object or return the replacement; the final wait performs a fresh lookup. If the application updates the existing node rather than replacing it, staleness may never occur, so wait instead for the relevant changed content, visibility, or other application-specific state.

Retry only when repeating the action is safe

A narrow retry can help when a brief DOM replacement occurs between locating and using an element. Keep the locator, catch only StaleElementReferenceException, relocate the intended element, and retry only an operation that is safe to repeat. Selenium’s troubleshooting guidance describes this reacquire-and-retry approach.

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

save_locator = (By.ID, "save")

for attempt in range(2):
    button = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable(save_locator)
    )
    try:
        button.click()
        break
    except StaleElementReferenceException:
        if attempt == 1:
            raise

This is a bounded retry: it does not loop forever or discard the final error. Use it only if clicking again cannot duplicate a consequential action. For a form submission, payment, deletion, or other side effect, first determine whether the first attempt took effect; blindly repeating it may be incorrect even if the click raised an exception. If the locator now matches a different element, stop and correct the page state or locator rather than retrying.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the fix that matches the change

What changed What to wait for What to do next
Navigation or refresh A meaningful condition on the destination page Locate the target again in the new page context.
A dynamic update replaced a node staleness_of(old_element) if detachment is the expected event Find the replacement with its locator.
The current element must become usable Visibility or clickability using a locator Act promptly on the newly located element.
The frame or browsing context changed The correct page and frame state Switch to the intended current context, then locate again.

These patterns follow Selenium’s descriptions of stale references and expected conditions. The essential distinction is whether you are waiting for a usable current element, for the old one to disappear, or for the correct browsing context.

Troubleshoot common failures

The same exception returns after adding a sleep

A fixed pause neither proves the target is ready nor ensures it remains unchanged. Replace it with a wait for the needed state using a locator. If node replacement is part of the update, wait for staleness and then locate the new node.

The wait times out

Check that the locator matches the current page, that the browser is in the right frame, and that the chosen condition can become true. For example, a clickability wait will not succeed if the element remains disabled or hidden. If the application keeps an existing node and changes its contents, waiting for staleness is the wrong condition.

The replacement lookup finds the wrong element

Reassess whether the locator uniquely identifies the intended target in the updated page. If multiple elements match, refine the locator or scope it to the correct container; do not treat a successful lookup as proof that it is the right element.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A retry makes the problem worse

Remove broad catch-and-ignore logic and any unbounded retry loop. Confirm whether the operation is safe to repeat, preserve the last exception, and inspect whether navigation, a DOM update, or a context change explains the stale reference. Retrying cannot correct a wrong locator or wrong page state.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance and reliability considerations

Explicit waits poll for a condition instead of sleeping for an assumed duration. This lets the script continue when the required state is observed and wait longer when it is not yet ready, up to the timeout you set. The example uses a 10-second timeout as a code choice, not a universal Selenium requirement; choose a limit suitable for your application and fail clearly if the condition never occurs.

Reliability comes from waiting for the state that matters and re-locating at the point of use. Avoid retaining element objects across operations that can replace page nodes. Do not catch every exception as if it were transient: a stale reference, a missing element, a timeout, and a wrong frame indicate different conditions and need different fixes.

Or skip the browser setup

If your goal is a screenshot rather than browser interaction, ScreenshotNeo can return a website capture through one GET request. Its clean-shot process accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers. It also provides an MCP server for AI agents, with take_screenshot, get_page_info, and capture_pdf tools.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Example using cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Use the ScreenshotNeo documentation for API options and setup. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for 1,000 free screenshots a month, with no card.

FAQ

Does a stale element mean Selenium lost the whole page?

No. It means the particular element reference can no longer be used in the current DOM or page context. Other elements may remain accessible, but confirm the correct page and frame before continuing.

Can I reuse a stale WebElement after waiting?

No. A wait can detect a state change, but the old reference does not become current again. Locate the element again.

Is there a published frequency for this exception?

The cited Selenium documentation explains the exception and its causes but does not provide a prevalence statistic.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.