> ## Documentation Index
> Fetch the complete documentation index at: https://docs.meter.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> Exception handling and error codes in the Meter Python SDK

# Error Handling

The Meter SDK uses exceptions to signal errors. All API-related errors raise `MeterError`, which you should catch and handle appropriately.

## MeterError

The base exception for all Meter SDK errors.

```python theme={null}
from meter_sdk import MeterError

class MeterError(Exception):
    """Base exception for Meter SDK errors"""
    pass
```

### Catching errors

```python theme={null}
from meter_sdk import MeterClient, MeterError

client = MeterClient(api_key="sk_live_...")

try:
    strategy = client.generate_strategy(
        url="https://example.com",
        description="Extract data",
        name="Test Strategy"
    )
except MeterError as e:
    print(f"API error: {e}")
    # Handle error appropriately
```

## Common error scenarios

### 401 Unauthorized

**Cause:** Invalid or missing API key

```python theme={null}
try:
    client = MeterClient(api_key="invalid_key")
    strategies = client.list_strategies()
except MeterError as e:
    # "Invalid or missing API key"
    print(f"Authentication failed: {e}")
```

**Solutions:**

* Verify your API key is correct
* Check that the key hasn't been deleted
* Ensure you're using the full key (starts with `sk_live_`)

### 400 Bad Request

**Cause:** Invalid request parameters

```python theme={null}
try:
    # Missing required parameter
    strategy = client.generate_strategy(
        url="https://example.com",
        description="",  # Empty description
        name="Test"
    )
except MeterError as e:
    # "Invalid request parameters"
    print(f"Validation error: {e}")
```

**Solutions:**

* Check all required parameters are provided
* Verify parameter types are correct
* Ensure values are valid (e.g., URL is well-formed)

### 404 Not Found

**Cause:** Resource doesn't exist

```python theme={null}
try:
    strategy = client.get_strategy("invalid-uuid")
except MeterError as e:
    # "Strategy not found"
    print(f"Resource not found: {e}")
```

**Solutions:**

* Verify the UUID is correct
* Check the resource hasn't been deleted
* Ensure you have permission to access the resource

### 429 Too Many Requests

**Cause:** Rate limit exceeded on strategy generation

```python theme={null}
try:
    strategy = client.generate_strategy(url, description, name)
except MeterError as e:
    # "Please slow down - limits on strategy generation"
    print(f"Rate limited: {e}")
```

**Solutions:**

* Wait before retrying (the API returns a `Retry-After` header with seconds to wait)
* Reduce request frequency
* Use exponential backoff

### 500 Internal Server Error

**Cause:** Server-side error

```python theme={null}
try:
    job = client.create_job(strategy_id, url)
except MeterError as e:
    # "Internal server error"
    print(f"Server error: {e}")
```

**Solutions:**

* Retry the request after a short delay
* If persistent, contact support
* Check API status page for incidents

### 503 Service Unavailable

**Cause:** LLM service temporarily unavailable

```python theme={null}
try:
    strategy = client.generate_strategy(url, description, name)
except MeterError as e:
    # "Service temporarily unavailable"
    print(f"Service unavailable: {e}")
```

**Solutions:**

* Retry the request after 30-60 seconds
* This is usually temporary

## Timeout errors

When waiting for jobs with a timeout:

```python theme={null}
from meter_sdk import MeterError

try:
    completed = client.wait_for_job(
        job_id,
        timeout=60.0  # 1 minute
    )
except MeterError as e:
    # "Job timed out after 60 seconds"
    print(f"Timeout: {e}")

    # Check job status manually
    job = client.get_job(job_id)
    if job['status'] == 'failed':
        print(f"Job failed: {job['error']}")
    else:
        print(f"Job still {job['status']}, wait longer")
```

## Best practices

### Always catch MeterError

```python theme={null}
from meter_sdk import MeterClient, MeterError

client = MeterClient(api_key="sk_live_...")

try:
    # API calls
    strategy = client.generate_strategy(url, description, name)
    job = client.create_job(strategy['strategy_id'], url)
    result = client.wait_for_job(job['job_id'])

except MeterError as e:
    # Log error
    logger.error(f"Meter API error: {e}")

    # Handle appropriately
    send_alert(f"Scraping failed: {e}")
```

### Implement retry logic

For transient errors (429, 500, 503, network issues):

```python theme={null}
import time
from meter_sdk import MeterError

def generate_strategy_with_retry(client, url, description, name, max_retries=3):
    """Generate strategy with retry logic"""
    for attempt in range(max_retries):
        try:
            return client.generate_strategy(url, description, name)
        except MeterError as e:
            error_str = str(e).lower()

            # Rate limited - wait longer (respect Retry-After)
            if "429" in str(e) or "slow down" in error_str:
                wait_time = 60  # Default from Retry-After header
                print(f"Rate limited. Waiting {wait_time}s...")
                time.sleep(wait_time)
                continue

            # Server errors - exponential backoff
            if "500" in str(e) or "503" in str(e) or "unavailable" in error_str:
                if attempt < max_retries - 1:
                    wait_time = 2 ** attempt
                    print(f"Retry {attempt + 1}/{max_retries} in {wait_time}s")
                    time.sleep(wait_time)
                else:
                    raise  # Max retries exceeded
            else:
                raise  # Non-retryable error
```

### Graceful degradation

Handle errors without crashing:

```python theme={null}
from meter_sdk import MeterError

def fetch_latest_data(client, schedule_id):
    """Fetch changes with fallback"""
    try:
        changes = client.get_schedule_changes(schedule_id)
        return changes['changes']

    except MeterError as e:
        logger.warning(f"Failed to fetch changes: {e}")

        # Fallback: use cached data
        return load_from_cache(schedule_id)
```

### Log errors for debugging

```python theme={null}
import logging
from meter_sdk import MeterError

logger = logging.getLogger(__name__)

try:
    strategy = client.generate_strategy(url, description, name)
except MeterError as e:
    # Log with context
    logger.error(
        "Strategy generation failed",
        extra={
            "url": url,
            "description": description,
            "error": str(e)
        }
    )
    raise
```

## Error response format

API errors return JSON with details:

```json theme={null}
{
  "detail": "Error message describing what went wrong"
}
```

The SDK extracts this message and includes it in the `MeterError` exception.

## Handling specific error types

### Strategy generation failures

```python theme={null}
try:
    strategy = client.generate_strategy(url, description, name)
except MeterError as e:
    if "not accessible" in str(e).lower():
        print("URL cannot be accessed. Check if it's public.")
    elif "invalid url" in str(e).lower():
        print("URL format is invalid")
    else:
        print(f"Generation failed: {e}")
```

### Job failures

```python theme={null}
job = client.get_job(job_id)

if job['status'] == 'failed':
    error = job['error']

    if "selector not found" in error.lower():
        print("Website structure changed. Regenerate strategy.")
    elif "timeout" in error.lower():
        print("Website took too long to respond")
    else:
        print(f"Job failed: {error}")
```

## Error monitoring

Set up error tracking for production:

```python theme={null}
import sentry_sdk
from meter_sdk import MeterError

sentry_sdk.init(dsn="your-sentry-dsn")

try:
    strategy = client.generate_strategy(url, description, name)
except MeterError as e:
    # Automatically captured by Sentry
    sentry_sdk.capture_exception(e)
    raise
```

## Next steps

<CardGroup cols={2}>
  <Card title="MeterClient Reference" icon="code" href="/api-reference/python/client">
    Explore all SDK methods
  </Card>

  <Card title="Quick Start" icon="rocket" href="/quickstart">
    See error handling in practice
  </Card>

  <Card title="Best Practices" icon="lightbulb" href="/concepts/overview">
    Learn SDK best practices
  </Card>

  <Card title="REST API Errors" icon="brackets-curly" href="/api-reference/rest/errors">
    View REST API error codes
  </Card>
</CardGroup>

## Need help?

Email me at [mckinnon@meter.sh](mailto:mckinnon@meter.sh)
