Skip to content
Selenium WebDriver · error message

Selenium: NoSuchElementException: Unable to locate element

RetryableLocating elements

Last verified

The exact message
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"#login"}; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#nosuchelementexception

What it means

find_element searched the current browsing context and nothing matched the locator at that moment. The JSON at the end shows exactly what the driver searched for. Note that By.ID, By.NAME and By.CLASS_NAME are translated into CSS selectors, so the method usually reads css selector even if you did not write CSS.

Without an implicit wait, find_element checks once and throws immediately. On pages that render with JavaScript, the element often appears a moment later, which is why this exception is so often a timing problem rather than a wrong locator. The other common causes are being in the wrong context (the element is in an iframe, a shadow root or another window) and the page simply being different from what you expected.

What is not wrong: the browser or driver setup. The session works; the search came up empty.

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)
wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID, "auth-frame")))
username = wait.until(EC.visibility_of_element_located((By.NAME, "username")))
username.send_keys("demo")
driver.switch_to.default_content()

Why it happens

  • The element had not been rendered yet when find_element ran.
  • The element is inside an iframe and the driver has not switched into it.
  • The element is inside a shadow root, which normal locators do not pierce.
  • The locator is wrong or depends on dynamic IDs or class names that changed.
  • The page is not the one you expect: a login redirect, consent screen or error page.

How to fix it

  1. Wait for the element: WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, 'login'))).
  2. If it is inside an iframe, switch first: WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, 'iframe#auth'))).
  3. For shadow DOM, locate the host and use host.shadow_root.find_element(By.CSS_SELECTOR, ...).
  4. Test the locator in DevTools with document.querySelectorAll() or $x() on the same page state.
  5. Log driver.current_url and save a screenshot on failure to confirm which page you were on.

How to stop it recurring

Use explicit waits for anything that appears after page load, and avoid mixing implicit and explicit waits, which Selenium's documentation warns can cause unpredictable wait times. Prefer stable attributes such as IDs, names or data-testid over generated class names. Make frame and shadow-root switches explicit in page objects.

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

Related errors

Definitions

Quick answers

What does "NoSuchElementException: Unable to locate element" mean in Selenium?

find_element searched the current browsing context and nothing matched the locator at that moment. The JSON at the end shows exactly what the driver searched for. Note that By.ID , By.NAME and By.CLASS_NAME are translated into CSS selectors, so the method usually reads css selector even if you did not write CSS. Without an implicit wait, find_element checks once and throws immediately.

How do I fix "NoSuchElementException: Unable to locate element"?

1. Wait for the element: WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, 'login'))). 2. If it is inside an iframe, switch first: WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, 'iframe#auth'))). 3. For shadow DOM, locate the host and use host.shadow_root.find_element(By.CSS_SELECTOR, ...). 4. Test the locator in DevTools with document.querySelectorAll() or $x() on the same page state. 5. Log driver.current_url and save a screenshot on failure to confirm which page you were on.

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.