Error Handling
The SDK provides comprehensive error handling with rich exception classes that provide context about what went wrong and how to handle it.
Exception Hierarchy
The SDK provides a comprehensive hierarchy of exception classes that map to different types of errors. Import the exceptions you need:
Import Exceptions
from nexla_sdk.exceptions import (
NexlaAPIError,
AuthenticationError,
AuthorizationError,
NotFoundError,
ValidationError,
RateLimitError,
ResourceConflictError,
ServerError
)
HTTP Error Mapping
The SDK automatically maps HTTP status codes to appropriate exception classes, providing rich context about what went wrong:
- 400 →
ValidationError - 401 →
AuthenticationError - 403 →
AuthorizationError - 404 →
NotFoundError - 409 →
ResourceConflictError - 429 →
RateLimitError(withretry_afterif available) - 5xx →
ServerError
Basic Error Handling
Basic Error Handling
from nexla_sdk import NexlaClient
from nexla_sdk.exceptions import NexlaAPIError, AuthenticationError
client = NexlaClient()
try:
# This might fail if flow doesn't exist
flow = client.flows.get("non-existent-flow-id")
except AuthenticationError:
print("❌ Authentication failed - check your credentials")
except NexlaAPIError as e:
print(f"❌ API Error: {e.message}")
print(f"Status Code: {e.status_code}")
except Exception as e:
print(f"❌ Unexpected error: {e}")
Advanced Error Handling
Safe API Calls with Retries
Safe API Call with Retries
from nexla_sdk.exceptions import NexlaAPIError, AuthenticationError, RateLimitError
import time
def safe_api_call_with_retries(func, max_retries=3):
"""Execute API call with automatic retries"""
for attempt in range(max_retries):
try:
return func()
except AuthenticationError:
print("❌ Authentication failed:")
print(" • Check your NEXLA_SERVICE_KEY")
print(" • Verify the key is active")
print(" • Ensure you have proper permissions")
raise # Don't retry auth errors
except RateLimitError as e:
wait_time = e.retry_after or (2 ** attempt) # Exponential backoff
print(f"⏳ Rate limited. Waiting {wait_time}s before retry {attempt + 1}/{max_retries}")
if attempt < max_retries - 1:
time.sleep(wait_time)
continue
else:
raise
except NexlaAPIError as e:
print(f"❌ API Error (Status {e.status_code}): {e.message}")
if e.status_code >= 500 and attempt < max_retries - 1:
# Retry server errors
wait_time = 2 ** attempt
print(f"⏳ Server error. Retrying in {wait_time}s...")
time.sleep(wait_time)
continue
else:
raise
except Exception as e:
print(f"❌ Unexpected error: {e}")
raise
# Usage example
def get_flows():
return client.flows.list()
flows = safe_api_call_with_retries(get_flows)
Resource Conflict Handling
Resource Conflict Handling
from nexla_sdk.exceptions import ResourceConflictError
def create_or_update_destination(payload):
"""Create destination or update if it already exists"""
try:
destination = client.destinations.create(payload)
print(f"✅ Created new destination: {destination.name}")
return destination
except ResourceConflictError:
print("⚠️ Destination already exists, updating instead...")
# Find existing destination
existing = client.destinations.list(name=payload["name"], per_page=1)
if existing:
destination = client.destinations.update(existing[0].id, payload)
print(f"✅ Updated existing destination: {destination.name}")
return destination
else:
raise Exception("Resource conflict but destination not found")
Error Context and Debugging
Exception Attributes
All SDK exceptions provide rich context:
Exception Context
try:
flow = client.flows.get("invalid-id")
except NexlaAPIError as e:
print(f"Operation: {e.operation}")
print(f"Resource Type: {e.resource_type}")
print(f"Resource ID: {e.resource_id}")
print(f"Status Code: {e.status_code}")
print(f"Message: {e.message}")
print(f"Retry After: {e.retry_after}")
Logging Errors
Error Logging
import logging
logger = logging.getLogger(__name__)
try:
flows = client.flows.list()
except NexlaAPIError as e:
logger.error(
f"API Error: {e.message}",
extra={
"operation": e.operation,
"resource_type": e.resource_type,
"resource_id": e.resource_id,
"status_code": e.status_code
}
)
raise
Best Practices
1. Always Handle Authentication Errors
Auth Error Handling
try:
flows = client.flows.list()
except AuthenticationError:
# Don't retry auth errors - they won't succeed
logger.error("Authentication failed - check credentials")
sys.exit(1)
2. Implement Exponential Backoff for Rate Limits
Rate Limit Backoff
import time
from nexla_sdk.exceptions import RateLimitError
def with_backoff(func, max_retries=5):
for attempt in range(max_retries):
try:
return func()
except RateLimitError as e:
wait_time = e.retry_after or (2 ** attempt)
if attempt < max_retries - 1:
time.sleep(wait_time)
continue
raise
3. Log All Errors with Context
Comprehensive Logging
def log_error_with_context(e, operation="unknown"):
logger.error(
f"Error in {operation}: {str(e)}",
extra={
"error_type": type(e).__name__,
"operation": operation,
"traceback": traceback.format_exc()
}
)
Next Steps
- Rate Limits & Retries - Handling rate limiting and retries
- Troubleshooting - Common issues and solutions
- Operations - Monitoring and observability
Learn More
For detailed error handling patterns and retry strategies, see the Error Handling & Retries page in our Nexla SDK guides.