Skip to main content

Overview

Nova Act provides a comprehensive error hierarchy that helps you handle different failure scenarios appropriately. Understanding the error types allows you to implement robust retry logic and graceful failure handling.

Error Hierarchy

All Nova Act errors inherit from ActError, which provides metadata about the failed operation:
from nova_act import ActError

try:
    # Some operation
    pass
except ActError as e:
    print(f"Error: {e.message}")
    print(f"Metadata: {e.metadata}")

Error Categories

Indicates the requested prompt cannot be completed in the given configuration. You may retry with a different request.Subclasses:
  • ActInvalidModelGenerationError - Model output could not be processed
  • ActInvalidToolError - Model attempted to call unknown tool
  • ActInvalidToolSchemaError - Tool call failed schema validation
  • ActAgentFailed - Agent raised an error because task was not possible
  • ActExceededMaxStepsError - Exceeded maximum allowed steps
  • NoHumanInputToolAvailable - Model requested human input but no callbacks provided
Indicates a local error encountered while executing valid output from the agent.Subclasses:
  • ActActuationError - Failed to actuate a command from the agent
  • ActToolError - Failure running a tool
  • ActMCPError - Failure running an MCP-provided tool
  • ActCanceledError - User canceled execution
  • ApproveCanceledError - Canceled during human approval
  • UiTakeoverCanceledError - Canceled during UI takeover
  • ActStateGuardrailError - Blocked by state guardrail
Indicates a bad request to NovaAct Service. You may retry with a different request.Subclasses:
  • ActBadRequestError - Bad request to /step endpoint
  • ActGuardrailsError - Request blocked by agent guardrails
  • ActRateLimitExceededError - Request throttled due to quota limits
  • ActRequestThrottledError - Too many requests in short time period
  • ActDailyQuotaExceededError - Daily quota exceeded
Indicates the NovaAct Service encountered an error. Report to customer support.Subclasses:
  • ActBadResponseError - Bad response from /step endpoint
  • ActServiceUnavailableError - Service currently unavailable
  • ActInternalServerError - Internal server error occurred

Basic Error Handling

Catch All Act Errors

from nova_act import NovaAct, ActError

with NovaAct(starting_page="https://example.com") as nova:
    try:
        result = nova.act("Search for products")
    except ActError as e:
        print(f"Act failed: {e}")
        # Handle the error appropriately

Handle Specific Errors

from nova_act import (
    NovaAct,
    ActAgentError,
    ActExceededMaxStepsError,
    ActRateLimitExceededError,
    ActInvalidModelGenerationError
)

with NovaAct(starting_page="https://example.com") as nova:
    try:
        result = nova.act("Complete a complex task")
    except ActExceededMaxStepsError:
        print("Task too complex - try breaking it into smaller steps")
    except ActRateLimitExceededError:
        print("Rate limited - waiting before retry")
        time.sleep(60)
    except ActInvalidModelGenerationError as e:
        print(f"Model output invalid: {e.raw_response}")
    except ActAgentError:
        print("Agent couldn't complete task - revise prompt")

Retry Patterns

Simple Retry

import time
from nova_act import NovaAct, ActError

def act_with_retry(nova, prompt, max_retries=3):
    """Retry act() on failure."""
    for attempt in range(max_retries):
        try:
            return nova.act(prompt)
        except ActError as e:
            if attempt == max_retries - 1:
                raise
            print(f"Attempt {attempt + 1} failed: {e}")
            time.sleep(2 ** attempt)  # Exponential backoff

with NovaAct(starting_page="https://example.com") as nova:
    result = act_with_retry(nova, "Search for products")

Retry with Exponential Backoff

import time
from nova_act import NovaAct, ActError, ActRateLimitExceededError

def exponential_backoff_retry(nova, prompt, max_retries=5):
    """Retry with exponential backoff."""
    base_delay = 1
    
    for attempt in range(max_retries):
        try:
            return nova.act(prompt)
        except ActRateLimitExceededError:
            if attempt == max_retries - 1:
                raise
            
            delay = base_delay * (2 ** attempt)
            print(f"Rate limited. Waiting {delay}s before retry...")
            time.sleep(delay)
        except ActError as e:
            if attempt == max_retries - 1:
                raise
            print(f"Attempt {attempt + 1} failed: {e}")
            time.sleep(1)

with NovaAct(starting_page="https://example.com") as nova:
    result = exponential_backoff_retry(nova, "Process data")

Conditional Retry

from nova_act import (
    NovaAct,
    ActError,
    ActAgentError,
    ActServerError,
    ActRateLimitExceededError
)

def should_retry(error: ActError) -> bool:
    """Determine if error is retryable."""
    # Retry rate limits and server errors
    if isinstance(error, (ActRateLimitExceededError, ActServerError)):
        return True
    
    # Don't retry agent errors - need to change prompt
    if isinstance(error, ActAgentError):
        return False
    
    return True

def act_with_conditional_retry(nova, prompt, max_retries=3):
    """Retry only for retryable errors."""
    for attempt in range(max_retries):
        try:
            return nova.act(prompt)
        except ActError as e:
            if not should_retry(e) or attempt == max_retries - 1:
                raise
            
            print(f"Retryable error: {e}")
            time.sleep(2 ** attempt)

with NovaAct(starting_page="https://example.com") as nova:
    result = act_with_conditional_retry(nova, "Complete task")

Retry with Alternative Prompts

from nova_act import NovaAct, ActAgentError

def act_with_fallback_prompts(nova, prompts: list[str]):
    """Try alternative prompts if primary fails."""
    last_error = None
    
    for i, prompt in enumerate(prompts):
        try:
            print(f"Trying prompt {i + 1}/{len(prompts)}...")
            return nova.act(prompt)
        except ActAgentError as e:
            print(f"Prompt {i + 1} failed: {e}")
            last_error = e
            continue
    
    # All prompts failed
    raise last_error

with NovaAct(starting_page="https://example.com") as nova:
    result = act_with_fallback_prompts(nova, [
        "Click the blue Submit button at the bottom",
        "Click the Submit button",
        "Submit the form by pressing Enter",
    ])

Workflow-Level Error Handling

Handle Workflow Errors

from nova_act import NovaAct, workflow, ActError

@workflow(
    workflow_definition_name="my-workflow",
    model_id="nova-act-latest",
)
def resilient_workflow():
    """Workflow with comprehensive error handling."""
    try:
        with NovaAct(starting_page="https://example.com") as nova:
            # Step 1
            try:
                nova.act("Navigate to login")
            except ActError as e:
                print(f"Navigation failed: {e}")
                # Try alternative navigation
                nova.go_to_url("https://example.com/login")
            
            # Step 2
            try:
                result = nova.act_get("Get account balance")
                return result.response
            except ActError as e:
                print(f"Failed to get balance: {e}")
                # Return default value
                return "N/A"
    
    except Exception as e:
        print(f"Workflow failed: {e}")
        # Log error, send alert, etc.
        raise

if __name__ == "__main__":
    try:
        result = resilient_workflow()
        print(f"Result: {result}")
    except Exception as e:
        print(f"Fatal error: {e}")

Circuit Breaker Pattern

import time
from dataclasses import dataclass
from datetime import datetime, timedelta
from nova_act import NovaAct, ActError

@dataclass
class CircuitBreaker:
    """Circuit breaker for rate-limited operations."""
    failure_threshold: int = 3
    timeout: int = 60  # seconds
    
    _failure_count: int = 0
    _last_failure_time: datetime | None = None
    _is_open: bool = False
    
    def call(self, func, *args, **kwargs):
        """Call function with circuit breaker protection."""
        # Check if circuit is open
        if self._is_open:
            if datetime.now() - self._last_failure_time < timedelta(seconds=self.timeout):
                raise Exception("Circuit breaker is open")
            else:
                # Try to close circuit
                self._is_open = False
                self._failure_count = 0
        
        try:
            result = func(*args, **kwargs)
            # Success - reset failure count
            self._failure_count = 0
            return result
        
        except ActError as e:
            self._failure_count += 1
            self._last_failure_time = datetime.now()
            
            if self._failure_count >= self.failure_threshold:
                self._is_open = True
                print(f"Circuit breaker opened after {self._failure_count} failures")
            
            raise

# Usage
circuit_breaker = CircuitBreaker(failure_threshold=3, timeout=60)

with NovaAct(starting_page="https://example.com") as nova:
    try:
        result = circuit_breaker.call(nova.act, "Process data")
    except Exception as e:
        print(f"Operation failed: {e}")

Timeout Handling

Set Act Timeout

from nova_act import NovaAct, ActTimeoutError

with NovaAct(starting_page="https://example.com") as nova:
    try:
        # Set timeout for long-running task
        result = nova.act(
            "Complete complex multi-step task",
            timeout=300  # 5 minutes
        )
    except ActTimeoutError:
        print("Task timed out - may need to simplify")

Set Max Steps

from nova_act import NovaAct, ActExceededMaxStepsError

with NovaAct(starting_page="https://example.com") as nova:
    try:
        # Limit number of steps
        result = nova.act(
            "Search and filter products",
            max_steps=20  # Default is 30
        )
    except ActExceededMaxStepsError:
        print("Task exceeded max steps - break into smaller tasks")

Logging Errors

Log to File

import logging
from nova_act import NovaAct, ActError

# Configure logging
logging.basicConfig(
    filename='nova_act_errors.log',
    level=logging.ERROR,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

with NovaAct(starting_page="https://example.com") as nova:
    try:
        result = nova.act("Process data")
    except ActError as e:
        logger.error(
            f"Act failed",
            exc_info=True,
            extra={
                'error_type': type(e).__name__,
                'message': e.message,
                'metadata': e.metadata,
            }
        )
        raise

Structured Error Reporting

import json
from datetime import datetime
from nova_act import NovaAct, ActError

def log_error_structured(error: ActError, context: dict):
    """Log error in structured format."""
    error_data = {
        'timestamp': datetime.now().isoformat(),
        'error_type': type(error).__name__,
        'message': error.message,
        'metadata': {
            'session_id': error.metadata.session_id if error.metadata else None,
            'act_id': error.metadata.act_id if error.metadata else None,
            'num_steps': error.metadata.num_steps_executed if error.metadata else None,
        },
        'context': context,
    }
    
    # Log to file
    with open('errors.jsonl', 'a') as f:
        f.write(json.dumps(error_data) + '\n')
    
    # Or send to monitoring service
    # send_to_monitoring(error_data)

with NovaAct(starting_page="https://example.com") as nova:
    try:
        result = nova.act("Process data")
    except ActError as e:
        log_error_structured(e, {
            'workflow': 'data_processing',
            'url': nova.page.url,
        })
        raise

Best Practices

Categorize Errors

Handle different error categories appropriately:
  • AgentError: Revise prompt or break into smaller steps
  • ClientError: Check input or wait for rate limits
  • ServerError: Report to support
  • ExecutionError: Check local environment

Use Exponential Backoff

Implement exponential backoff for retries:
delay = base_delay * (2 ** attempt)
time.sleep(delay)

Set Reasonable Limits

Configure appropriate timeouts and max steps:
nova.act(
    "Complex task",
    timeout=300,
    max_steps=20
)

Log for Debugging

Always log errors with context:
logger.error(f"Failed at step {step}", exc_info=True)

Troubleshooting Common Errors

Cause: Task requires more steps than allowedSolutions:
  • Break task into smaller act() calls
  • Increase max_steps parameter
  • Provide more specific prompts
  • Add hints to guide the agent
Cause: Too many requests in short timeSolutions:
  • Implement exponential backoff
  • Reduce request rate
  • Consider upgrading to AWS Nova Act service
Cause: Model produced invalid outputSolutions:
  • Simplify the prompt
  • Use more specific instructions
  • Retry with alternative prompt
  • Check if schema is too complex
Cause: Agent attempted to access blocked URLSolutions:
  • Review guardrail configuration
  • Add required domains to allowlist
  • Adjust prompts to avoid blocked sites

Next Steps

Logging & Traces

View detailed traces to debug errors

Deployment

Handle errors in production deployments

Parallel Sessions

Error handling for concurrent workflows

Security

Handle security-related errors

Build docs developers (and LLMs) love