Selenium "NoSuchElementException: Unable to locate element" in CI
find_element looks for the element once, immediately. In CI the page is often slower to render than on a developer machine, so the element is not in the DOM yet and Selenium raises NoSuchElementException. An explicit wait removes the race.
What this error means
A test fails with "selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element" naming the selector. It passes locally but flakes in CI.
selenium.common.exceptions.NoSuchElementException: Message: no such element:
Unable to locate element: {"method":"css selector","selector":"#submit"}
(Session info: chrome=126.0.6478.126)Common causes
The element has not rendered yet
CI runners are slower and contended, so an element that exists by the time you query it locally is still being rendered when find_element runs in CI.
The selector matches inside a frame or shadow root
The node lives in an iframe or a shadow DOM not yet switched into, so it is genuinely not findable from the current context.
How to fix it
Replace immediate lookups with explicit waits
- Wrap the lookup in WebDriverWait with an expected condition.
- Wait for presence or visibility rather than calling find_element directly.
- Re-run; the wait polls until the element appears or times out cleanly.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
el = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "#submit")))Switch into the correct frame first
If the element is inside an iframe, switch to it before locating, then switch back to the default content afterwards.
driver.switch_to.frame("payment-iframe")
driver.find_element(By.CSS_SELECTOR, "#submit")
driver.switch_to.default_content()How to prevent it
- Use explicit waits for every element that loads asynchronously.
- Avoid implicit waits mixed with explicit waits; they compound unpredictably.
- Switch into frames or shadow roots before locating nodes inside them.