Selenium IndexError on find_elements[0]: Fix (2026)

You called driver.find_elements(By.CSS_SELECTOR, ".price")[0].text and Python crashed with IndexError because the page hadn’t finished loading or the selector matched zero elements. Selenium’s find_elements (plural) returns an empty list when nothing matches, vs find_element (singular) which raises NoSuchElementException.

Selenium IndexError on find_elements[0] Fix (2026)
Selenium IndexError on find_elements[0] Fix (2026)

📌 Quick answer: Use WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".price"))) to wait until the element appears (up to 10 sec). For “first match” use find_element (singular). Never index into find_elements without checking the list is non-empty.

Cause 1: Element not loaded yet

JavaScript-rendered pages need time. find_elements runs immediately and gets nothing.

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

# ❌ Element not yet on page
price = driver.find_elements(By.CSS_SELECTOR, ".price")[0].text

# ✓ Wait up to 10 sec
WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, ".price"))
)
price = driver.find_element(By.CSS_SELECTOR, ".price").text

Cause 2: Wrong selector or A/B test variant

Selector matches in your test environment but not in production due to CSS class change or A/B test.

# Use multiple fallback selectors
selectors = [".price", ".product-price", "[data-test='price']"]
for sel in selectors:
    els = driver.find_elements(By.CSS_SELECTOR, sel)
    if els:
        price = els[0].text
        break
else:
    price = None

Cause 3: find_element vs find_elements confusion

find_element raises NoSuchElementException on no match. find_elements returns empty list.

from selenium.common.exceptions import NoSuchElementException

try:
    price = driver.find_element(By.CSS_SELECTOR, ".price").text
except NoSuchElementException:
    price = None
# Or just use find_elements and check
els = driver.find_elements(By.CSS_SELECTOR, ".price")
price = els[0].text if els else None

Prevention

  1. Default to WebDriverWait + presence_of_element_located for any JS-rendered content
  2. Use find_element (singular) when you expect exactly one match
  3. Use find_elements (plural) + iterate when zero or more matches are acceptable
  4. Catch NoSuchElementException on find_element instead of bare except
Quick step-by-step summary (click to expand)
  1. Check the results list before indexing. Use if elements: first_element = elements[0] after calling driver.find_elements.
  2. Wait for elements before searching. Use WebDriverWait with expected_conditions.presence_of_all_elements_located to ensure elements are loaded before find_elements returns.
  3. Verify your CSS or XPath selector matches. Copy the selector and paste into browser DevTools console with document.querySelectorAll to preview matches.
  4. Handle timing issues with explicit retry. For flaky pages, wrap find_elements in a retry loop with a short sleep between attempts.

Frequently Asked Questions

Why IndexError happens

List index out of range means you accessed my_list[i] beyond the list’s actual length. Python lists are indexed from 0 to len(list)-1.

Common triggers

  • Off-by-one. my_list[len(my_list)] fails — use len(my_list) - 1.
  • Empty container. my_list[0] fails when the list is empty.
  • Wrong data source. CSV had fewer columns than expected.
  • Loop range wrong. for i in range(len(my_list) + 1) — off-by-one.
  • API returned empty result. Unhandled empty response.

Diagnostic pattern

# BAD — accessing first element without check
def get_first(items):
    return items[0]     # IndexError if items is empty

# GOOD — guard for empty
def get_first(items):
    if not items:
        return None
    return items[0]

# BETTER — use Optional and let caller handle
from typing import Optional, Sequence, TypeVar
T = TypeVar("T")

def get_first(items: Sequence[T]) -> Optional[T]:
    return items[0] if items else None

# For pandas, use .iloc with .empty check
import pandas as pd
def first_row(df: pd.DataFrame) -> Optional[dict]:
    if df.empty:
        return None
    return df.iloc[0].to_dict()

# For enumerate-based loops, this is safe
for i, item in enumerate(items):
    print(i, item)      # never IndexError

# Never write: for i in range(len(items) + 1)

Best practices

  • Prefer enumerate over range(len()). Never off-by-one.
  • Guard empty containers. Return None or default before accessing.
  • Use slicing. items[:5] is safe even if items has fewer than 5 elements.
  • Use type hints with Optional. Communicates that the value may not exist.
  • Use pytest with edge cases. Test empty lists, single-element lists, off-by-one boundaries.
What’s the difference between find_element and find_elements in Selenium?

find_element (singular) returns the first match or raises NoSuchElementException. find_elements (plural) returns a list of all matches (possibly empty). For one element use find_element; for multiple use find_elements with iteration.

How do I wait for an element to appear before accessing it?

Use WebDriverWait: WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, ‘.price’))). It polls every 500ms for up to 10 seconds and raises TimeoutException if the element doesn’t appear.

What’s the difference between presence_of_element_located and visibility_of_element_located?

presence_of: the element exists in the DOM (may be hidden). visibility_of: the element exists AND has non-zero size AND display is not ‘none’. Use visibility when you intend to click/read; presence when DOM existence is enough.

How do I handle Selenium A/B test variants with different selectors?

Try each selector in a loop with a list of fallbacks. for sel in [primary, fallback1, fallback2]: els = driver.find_elements(…); if els: break. Don’t rely on a single selector in production scrapers.

Why does my Selenium test work locally but fail in CI?

Usually timing: CI environments are slower, so explicit waits become critical. Replace any time.sleep() with WebDriverWait. Also check headless mode differences and screen resolution affecting visibility checks.

Adrian Mercurio


Full-Stack Developer at PIES IT Solution

Specializes in building complete capstone projects with full documentation. Strong background in PHP/MySQL development and database design. Has personally built and tested over 30 capstone-ready projects with ER diagrams, DFDs, and chapter-by-chapter thesis documentation.

Expertise: PHP · Laravel · Database Design · Capstone Projects · C# · C · C++ · Python · AI Projects
 · View all posts by Adrian Mercurio →

Leave a Comment