How to Fix “Element not interactable” Exception in Selenium

Element Not Interactable Exception In Selenium

Interacting with web elements is a core part of automating browsers with Selenium. However, you may occasionally run into the frustrating “element not interactable” exception when trying to click, send keys, or otherwise interact with an element on a page.

In this comprehensive guide, you’ll learn what causes this error and the various ways to fix it. We’ll cover specific solutions like waits and actions chains as well as general troubleshooting techniques you can follow to debug “element not interactable” issues.

Also read: Fixing “ImportError: No module named ‘selenium’” in Python

Understanding the Problem

The “element not interactable” error means Selenium attempted to interact with an element, but something on the page prevented that interaction from working properly.

Some common causes include:

  • The element is hidden by another overlaying element
  • The element exists in the DOM but is not visible in the viewport
  • There is a timing issue and the page has not finished loading and rendering the element

Without further troubleshooting, this generic error message gives us few clues about what exactly went wrong.

To fix it, we’ll need to employ waits and retries, debug the page layout and DOM, try alternative selectors and interaction methods, and leverage Selenium’s logs and screenshots.

Prerequisite Setup

Before we dig into solutions, let’s quickly cover the baseline dependencies and code to start debugging:

pip3 install selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import ElementNotInteractableException

driver = webdriver.Chrome()
driver.get("https://www.google.com")

try:
    button = driver.find_element(By.ID, "my-button")
    button.click()
except ElementNotInteractableException:
    print("Got ElementNotInteractableException!")

This sets up Selenium, opens a webpage, attempts to click a button, and prints an error message if the “element not interactable” exception occurs.

With that foundation in place, let’s walk through how to fix it.

Solution 1: Use Explicit and Implicit Waits

One of the most common sources of “element not interactable” errors is timing issues. The page may still be loading elements when Selenium attempts to interact with them.

Implicit waits tell Selenium to wait up to a certain amount of time when finding elements:

driver.implicitly_wait(10) # seconds

This will retry finding elements for up to 10 seconds before throwing an error.

Explicit waits go further and repeatedly check if an element meets a given condition, like being visible or enabled:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
import time

# Setup Chrome options
chrome_options = Options()

# Setup WebDriver with ChromeDriverManager
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)

# Navigate to the website
driver.get("https://python.org")

try:
    # Wait for the button to be clickable
    button = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.ID, "my-button"))
    )
    # Click the button once it's clickable
    button.click()

except:
    # Handle cases where the button is not found or not clickable within the timeout
    print("The button with ID 'my-button' was not found or was not clickable within 10 seconds.")

# It's good practice to close the browser when done
driver.quit()

This waits up to 10 seconds for the button to become clickable before interacting with it.

/usr/bin/python3 /Users/preet/test.py                                                                                                                                         
The button with ID 'my-button' was not found or was not clickable within 10 seconds.

Adding waits gives the page time to finish rendering elements before Selenium tries clicking or sending keys.

Solution 2: Use ActionChains to Move to the Element

Another issue could be that the element is buried or obscured by other elements on the page.

Selenium’s ActionChains allow you to virtually “move” the mouse to the element before interacting:

from selenium import webdriver
from selenium.webdriver import ActionChains

driver = webdriver.Chrome()
driver.get("https://python.org")

button = driver.find_element_by_id("my-button") 

actions = ActionChains(driver)
actions.move_to_element(button)
actions.click(button)
actions.perform()

This smoothly scrolls the element into view and hovers over it before clicking.

Also read: Important Python Selenium Functions You Must Know

Solution 3: Switch to the Frame Containing the Element

Web applications often embed iframes and frames to load distinct sections of pages. If your target element lives inside an iframe, you’ll need to explicitly switch driver context into that frame before interacting:

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://python.org")

# Locate the iframe using the updated method
iframe = driver.find_element(By.TAG_NAME, "iframe")
# Switch to the iframe
driver.switch_to.frame(iframe)

# Locate the button by its ID and click it
button = driver.find_element(By.ID, "my-button")
button.click()

# Switch back to the main content when done with the iframe
driver.switch_to.default_content()

This common cause of “element not interactable” errors can be easy to debug once you know to check for iframes!

Solution 4: Scroll Element into View Before Interacting

Another visibility issue could be elements loaded outside the current viewpoint that require scrolling to access:

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

driver = webdriver.Chrome()  # Ensure the ChromeDriver executable is in your PATH

driver.get("https://www.google.com")  # Navigate to Google

try:
    # Wait for the button to be present in the DOM and visible
    # Note: Google.com may not have a button with ID "my-button".
    # This is just an example and you might need to adjust the ID based on your actual requirements.
    button = WebDriverWait(driver, 10).until(
        EC.visibility_of_element_located((By.ID, "my-button"))
    )
    
    # Scroll the button into view
    driver.execute_script("arguments[0].scrollIntoView(true);", button)
    
    # Click the button
    button.click()
except TimeoutException:
    print("The button was not found on the page within the timeout period.")

Here we use JavaScript to manually scroll the DOM element into view before clicking it.

Solution 5: Try Alternative Selector Strategies

“Element not interactable” errors may indicate your selector isn’t pinpointing the desired element accurately.

Try alternative locator strategies like CSS selector, XPath, link text, partial link text, tag name etc. to hone in on the element:

from selenium.webdriver.common.by import By

button = driver.find_element(By.CSS_SELECTOR, "#content .submit-button")
button = driver.find_element(By.XPATH, "//button[text()='Submit']")

Experiment with different selection approaches if simpler lookups like ID and class name fail.

Solution 6: Debug Page Layout Issues in DevTools

At this point, it’s wise to open browser DevTools to inspect page layout and diagnose why your element remains “not interactable.”

Key things to validate:

  • Is the element visible and enabled from a user perspective?
  • Does the DOM markup around the element seem valid?
  • Are there unusual styles, overlays or opacity settings impacting visibility?

Comparison shots before and after interacting may reveal relevant style and layout changes.

Solution 7: Check Selenium Logs for Errors

Enable driver logging and scan logs following the “element not interactable” failure:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service

# Specify the path to your ChromeDriver and the log path
service = Service(executable_path="path/to/chromedriver", log_path="logs/service.log")

driver = webdriver.Chrome(service=service)

Logs may reveal additional errors and hints on root cause – invaluable debugging context!

Solution 8: Use Selenium Screenshots to Inspect State

Save browser screenshots immediately after the exception to visually inspect page state:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException

driver = webdriver.Chrome()  # Make sure the ChromeDriver executable is in your PATH

driver.get("https://www.google.com")  # Navigate to a website

try:
    # Attempt to find an element that does not exist
    driver.find_element(By.ID, "nonexistent-element-id")
except NoSuchElementException:
    # If the element is not found, save a screenshot
    driver.save_screenshot('after_error.png')

# Remember to close the driver after your tests
driver.quit()

Compare this to a working screenshot to identify differences in layout, rendering etc.

Solution 9: Switching Browser Driver Implementations

If you run into an “element not interactable” issue across browser drivers (ChromeDriver, GeckoDriver etc.), try switching driver implementations:

driver = webdriver.Firefox() # or Edge(), Safari() etc

This can rule out driver-specific quirks that may impact reliability.

Solution 10: Test Case to Isolate Failure

As a last resort, strip down the test case to the bare minimum steps to reproduce the failure:

  • Navigate to a blank HTML page
  • Insert minimal viable element markup
  • Attempt interaction

You may discover simplifying assumptions around page load status, element visibility, DOM stability etc.

This reduction often reveals underlying issues not evident in complex test flows.

Summary

Debugging the common “element not interactable” error may seem difficult at first glance. However, as shown in this guide’s solutions, applying the right mix of waits, actions, locators and troubleshooting techniques can uncover the root cause. Factor in timing, visibility and context issues as you investigate, and leverage the full suite of Selenium actions to interact with stubborn elements. With these tips, you’ll be able to tame even the most temperamental “not interactable” elements standing in the way of test automation success!