Skip to content
Selenium WebDriver · error message

Selenium: InvalidSelectorException: invalid selector

Permanent - do not retryLocating elements

Last verified

The exact message
selenium.common.exceptions.InvalidSelectorException: Message: invalid selector: An invalid or illegal selector was specified; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#invalidselectorexception

What it means

The driver could not use your locator because the selector itself is malformed or produces something that is not an element. It is a syntax problem, not a timing problem, so waiting longer will never fix it. Browsers report two main variants. For CSS: invalid selector: An invalid or illegal selector was specified. For XPath, a message that quotes your expression and says it is not a valid XPath expression, or one saying the result is [object Text] or [object Attr] and should be an element.

The XPath result variant is common in scraping code. Expressions ending in /text() or /@href are valid XPath, but WebDriver locators must return elements. Select the element and read .text or get_attribute('href') in code instead.

What is not wrong: the page. The same selector fails on every page.

What it looks like

from selenium.webdriver.common.by import By

# Invalid as a locator: returns attribute nodes
# driver.find_elements(By.XPATH, "//a[@class='product']/@href")

links = driver.find_elements(By.XPATH, "//a[@class='product']")
hrefs = [a.get_attribute("href") for a in links]

# Compound classes: use CSS, not CLASS_NAME
button = driver.find_element(By.CSS_SELECTOR, ".btn.btn-primary")

Why it happens

  • Unbalanced brackets or quotes in an XPath such as //div[@class='x'.
  • XPath ending in /text() or /@attribute, which returns a text or attribute node, not an element.
  • Using By.CLASS_NAME with a compound class string containing spaces.
  • Passing an XPath to By.CSS_SELECTOR or CSS to By.XPATH.
  • CSS selectors with unescaped special characters, such as IDs that start with a digit or contain a colon.

How to fix it

  1. Test the selector in DevTools: document.querySelectorAll('...') for CSS, $x("...") for XPath.
  2. Remove /text() or /@attr from the XPath and read the value in code: el.text or el.get_attribute('href').
  3. For multiple classes, use CSS: By.CSS_SELECTOR, '.btn.btn-primary' instead of By.CLASS_NAME with spaces.
  4. Match the By strategy to the selector syntax.
  5. Escape special characters in CSS, for example #\31 23 for id='123' or [id='a:b'] for colons.

How to stop it recurring

Validate selectors in DevTools before putting them in code, and keep locators in one place (page objects) so they are easy to test. Prefer short CSS selectors on stable attributes over long XPath expressions; reserve XPath for text matching and axis navigation that CSS cannot do.

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

Related errors

Definitions

Quick answers

What does "InvalidSelectorException: invalid selector" mean in Selenium?

The driver could not use your locator because the selector itself is malformed or produces something that is not an element. It is a syntax problem, not a timing problem, so waiting longer will never fix it. Browsers report two main variants. For CSS: invalid selector: An invalid or illegal selector was specified .

How do I fix "InvalidSelectorException: invalid selector"?

1. Test the selector in DevTools: document.querySelectorAll('...') for CSS, $x("...") for XPath. 2. Remove /text() or /@attr from the XPath and read the value in code: el.text or el.get_attribute('href'). 3. For multiple classes, use CSS: By.CSS_SELECTOR, '.btn.btn-primary' instead of By.CLASS_NAME with spaces. 4. Match the By strategy to the selector syntax. 5. Escape special characters in CSS, for example #\31 23 for id='123' or [id='a:b'] for colons.

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.