Skip to main content

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:

  • 400ValidationError
  • 401AuthenticationError
  • 403AuthorizationError
  • 404NotFoundError
  • 409ResourceConflictError
  • 429RateLimitError (with retry_after if available)
  • 5xxServerError

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

Learn More

For detailed error handling patterns and retry strategies, see the Error Handling & Retries page in our Nexla SDK guides.