Learn how to handle errors gracefully in your Sentience automation scripts. Build resilient automation that recovers from failures and provides meaningful error messages.
Web automation is inherently unreliable. Networks fail, pages change, elements disappear. Proper error handling makes your automation production-ready.
The most common error: an element you're looking for doesn't exist.
from sentience import snapshot, find, click
snap = snapshot(browser)
button = find(snap, "role=button text~'submit'")
# Good - check if element exists
if button:
click(browser, button.id)
else:
print("Submit button not found - form might have changed")
# Take alternative action or log error
# Also good - use try/except
try:
if not button:
raise ValueError("Submit button not found")
click(browser, button.id)
except ValueError as e:
print(f"Error: {e}")Operations that take too long should timeout gracefully:
from sentience import wait_for
# Wait with timeout
result = wait_for(browser, "role=heading text~'Success'", timeout=10.0)
if result.found:
print("Success message appeared!")
else:
print(f"Timeout: Success message didn't appear within 10 seconds")
# Log the timeout, retry, or take alternative action
# Handle long operations
try:
result = wait_for(browser, "text~'Processing complete'", timeout=60.0)
if not result.found:
raise TimeoutError("Processing didn't complete in time")
except TimeoutError as e:
print(f"Operation timed out: {e}")
# Retry or handle failureHandle network failures during page loads or API calls:
from sentience import SentienceBrowser, snapshot
import time
with SentienceBrowser(api_key="sk_...") as browser:
max_retries = 3
retry_count = 0
while retry_count < max_retries:
try:
browser.page.goto("https://example.com", timeout=30000)
snap = snapshot(browser)
break # Success
except Exception as e:
retry_count += 1
print(f"Network error (attempt {retry_count}/{max_retries}): {e}")
if retry_count >= max_retries:
print("Failed to load page after max retries")
raise
time.sleep(2) # Wait before retryimport time
def retry_with_backoff(func, max_retries=3, base_delay=1):
"""Retry a function with exponential backoff"""
for attempt in range(max_retries):
try:
return func()
except Exception as e:
if attempt == max_retries - 1:
raise # Last attempt failed
delay = base_delay * (2 ** attempt)
print(f"Retry {attempt + 1}/{max_retries} after {delay}s: {e}")
time.sleep(delay)
# Usage
def click_submit():
snap = snapshot(browser)
button = find(snap, "role=button text~'submit'")
if not button:
raise ValueError("Button not found")
click(browser, button.id)
retry_with_backoff(click_submit, max_retries=3, base_delay=2)from sentience import snapshot, find, click
snap = snapshot(browser)
# Try primary button first
submit_btn = find(snap, "role=button text~'Submit Form'")
if not submit_btn:
# Fallback: try alternative text
submit_btn = find(snap, "role=button text~'Submit'")
if not submit_btn:
# Fallback: try by importance
submit_btn = find(snap, "role=button importance>700")
if submit_btn:
click(browser, submit_btn.id)
else:
raise ValueError("Could not find submit button with any strategy")from sentience import snapshot, find, click, wait_for
def login(browser, email, password):
"""Login with error handling and graceful degradation"""
try:
# Navigate to login page
browser.page.goto("https://example.com/login")
# Wait for form to load
result = wait_for(browser, "role=textbox text~'email'", timeout=10.0)
if not result.found:
print("Warning: Login form didn't load, trying alternative path")
browser.page.goto("https://example.com/auth/login")
# Fill form
snap = snapshot(browser)
email_input = find(snap, "role=textbox text~'email'")
password_input = find(snap, "role=textbox text~'password'")
if not email_input or not password_input:
raise ValueError("Login form elements not found")
type_text(browser, email_input.id, email)
type_text(browser, password_input.id, password)
# Submit
submit_btn = find(snap, "role=button text~'log in'")
if submit_btn:
click(browser, submit_btn.id)
else:
# Fallback: press Enter
press_key(browser, "Enter")
# Verify success
result = wait_for(browser, "role=heading text~'Dashboard'", timeout=10.0)
return result.found
except Exception as e:
print(f"Login failed: {e}")
# Take screenshot for debugging
browser.page.screenshot(path="login_error.png")
return Falseimport logging
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Use in automation
def click_button(browser, query):
logger.info(f"Looking for button: {query}")
snap = snapshot(browser)
button = find(snap, query)
if button:
logger.info(f"Found button: {button.text}")
click(browser, button.id)
logger.info("Button clicked successfully")
else:
logger.error(f"Button not found: {query}")
raise ValueError(f"Button not found: {query}")# Take screenshot on error
try:
result = wait_for(browser, "role=button text~'submit'", timeout=5.0)
if not result.found:
browser.page.screenshot(path="element_not_found.png")
raise ValueError("Submit button not found")
except Exception as e:
browser.page.screenshot(path="error_state.png")
raise
# Good
button = find(snap, "role=button text~'submit'")
if button:
click(browser, button.id)
else:
# Handle missing element
# Avoid
button = find(snap, "role=button text~'submit'")
click(browser, button.id) # Might crash if button is None
# Short timeout for fast operations
result = wait_for(browser, "role=alert", timeout=2.0)
# Long timeout for slow operations
result = wait_for(browser, "text~'Report generated'", timeout=120.0)
# Good
if not button:
raise ValueError(f"Submit button not found with query: {query}. Page might have changed.")
# Avoid
if not button:
raise ValueError("Error")
from sentience import SentienceBrowser
# Use context manager for automatic cleanup
with SentienceBrowser(api_key="sk_...") as browser:
# Automation code
pass # Browser closes automatically
# Or manual cleanup
browser = SentienceBrowser(api_key="sk_...")
try:
# Automation code
finally:
browser.close() # Always close
Element not found or invalid query:
try:
button = find(snap, "role=button text~'submit'")
if not button:
raise ValueError("Submit button not found")
except ValueError as e:
print(f"Validation error: {e}")
Operation took too long:
try:
result = wait_for(browser, "text~'Success'", timeout=10.0)
if not result.found:
raise TimeoutError("Success message didn't appear")
except TimeoutError as e:
print(f"Timeout: {e}")
Network or navigation failures:
try:
browser.page.goto("https://example.com", timeout=30000)
except Exception as e:
print(f"Network error: {e}")
# Retry or fail gracefully