Error System
This document describes the error handling system in Atlas, which provides a structured approach to managing, categorizing, and responding to errors throughout the framework.
Overview
Atlas includes a robust error system with the following key features:
- Structured Error Hierarchy: Organized inheritance hierarchy of error types
- Error Categorization: Classification of errors by domain and severity
- Rich Error Information: Detailed error data including causes and contextual details
- Consistent Logging: Automatic mapping of error severity to log levels
- Error Recovery Tools: Utilities for safe execution and exception handling
- Serialization Support: Conversion of errors to dictionaries for API responses
The error system is designed to be:
- Informative: Providing clear context about what went wrong
- Actionable: Includes information about possible recovery strategies
- Consistent: Following predictable patterns across the codebase
- Extensible: Easy to add new error types for specific domains
Error Hierarchy
The error system is built around a base AtlasError
class with specialized subclasses:
AtlasError
├── ConfigurationError
├── APIError
├── ValidationError
├── AuthenticationError
└── ResourceError
Each error type provides specific fields and behavior relevant to its domain.
Core Components
Error Severity
The ErrorSeverity
enum defines how critical an error is:
from atlas.core.errors import ErrorSeverity
# Available severity levels
ErrorSeverity.INFO # Informational, not impacting operation
ErrorSeverity.WARNING # Minor issue that can be worked around
ErrorSeverity.ERROR # Issue that prevents operation but might be recoverable
ErrorSeverity.CRITICAL # Critical issue that cannot be recovered from
Error Categories
The ErrorCategory
enum classifies errors by their domain:
from atlas.core.errors import ErrorCategory
# Available categories
ErrorCategory.ENVIRONMENT # Environmental issues (file access, network, etc.)
ErrorCategory.CONFIGURATION # Configuration problems
ErrorCategory.VALIDATION # Input validation errors
ErrorCategory.API # API/external service errors
ErrorCategory.AUTH # Authentication/authorization errors
ErrorCategory.DATA # Data processing errors
ErrorCategory.LOGIC # Core algorithm/logic errors
ErrorCategory.RESOURCE # Resource constraints (memory, CPU, etc.)
ErrorCategory.UNKNOWN # Unknown/uncategorized errors
Base Error Class: AtlasError
The AtlasError
class is the foundation of the error system:
from atlas.core.errors import AtlasError, ErrorSeverity, ErrorCategory
# Create a basic error
error = AtlasError(
message="An error occurred",
severity=ErrorSeverity.ERROR,
category=ErrorCategory.UNKNOWN,
details={"context": "additional_information"},
cause=original_exception # Optional original exception
)
# Convert to dictionary (useful for API responses)
error_dict = error.to_dict()
# Log the error (automatically uses appropriate log level)
error.log()
Constructor Parameters
Parameter | Type | Description |
---|---|---|
message | str | The error message |
severity | ErrorSeverity | Severity level of the error |
category | ErrorCategory | Category of the error |
details | Optional[Dict[str, Any]] | Additional information about the error |
cause | Optional[Exception] | The original exception that caused this error |
Specialized Error Types
Atlas provides specialized error classes for common scenarios:
ConfigurationError
Used for issues with configuration settings:
from atlas.core.errors import ConfigurationError
# Create a configuration error
error = ConfigurationError(
message="Invalid database path configuration",
details={"setting": "db_path", "value": "/invalid/path"},
severity=ErrorSeverity.ERROR
)
APIError
Used for issues with external API calls:
from atlas.core.errors import APIError
# Create an API error
error = APIError(
message="Failed to connect to Anthropic API",
details={"endpoint": "/messages", "status_code": 503},
retry_possible=True # Indicate whether retry might succeed
)
ValidationError
Used for input validation issues:
from atlas.core.errors import ValidationError
# Create a validation error
error = ValidationError(
message="Invalid input parameters",
field_errors={
"max_tokens": ["Must be a positive integer"],
"model_name": ["Unknown model name: 'invalid-model'"]
},
severity=ErrorSeverity.WARNING
)
AuthenticationError
Used for authentication-related issues:
from atlas.core.errors import AuthenticationError
# Create an authentication error
error = AuthenticationError(
message="Invalid API key",
provider="anthropic",
details={"error_code": "invalid_api_key"}
)
ResourceError
Used for resource constraint issues:
from atlas.core.errors import ResourceError
# Create a resource error
error = ResourceError(
message="Database connection limit exceeded",
resource_type="database",
details={"limit": 100, "current": 105}
)
Utility Functions
The errors module provides several utility functions for error handling:
safe_execute
Executes a function safely with exception handling:
from atlas.core.errors import safe_execute, APIError
# Execute a function that might fail
result = safe_execute(
func=api_client.call_endpoint,
default={"fallback": "response"}, # Return this if the function fails
error_handler=lambda e: handle_api_error(e), # Optional custom handler
log_error=True, # Whether to log the error
error_cls=APIError, # What type of error to create
error_msg="Failed to call API endpoint", # Error message
# Arguments for the function:
endpoint="/messages",
payload={"user_message": "Hello"}
)
get_error_message
Extracts a formatted error message from an exception:
from atlas.core.errors import get_error_message
try:
# Some code that might fail
result = complex_operation()
except Exception as e:
# Get a clean error message
error_msg = get_error_message(e)
print(f"Operation failed: {error_msg}")
# Or with traceback
detailed_msg = get_error_message(e, include_traceback=True)
logger.error(detailed_msg)
convert_exception
Converts a standard Python exception to an AtlasError:
from atlas.core.errors import convert_exception, ValidationError
try:
# Some code that might fail
config = parse_config(config_file)
except (ValueError, KeyError) as e:
# Convert to a specific Atlas error type
atlas_error = convert_exception(
exception=e,
error_cls=ValidationError,
message="Invalid configuration format",
severity=ErrorSeverity.ERROR,
category=ErrorCategory.CONFIGURATION,
details={"config_file": config_file}
)
# Now you can use Atlas error features
atlas_error.log()
return {"error": atlas_error.to_dict()}
Common Usage Patterns
Catching and Converting Exceptions
A common pattern is to catch standard exceptions and convert them to Atlas errors:
from atlas.core.errors import APIError, convert_exception
def call_llm_api(prompt, model):
try:
# Call external API
response = client.generate(prompt=prompt, model=model)
return response
except requests.Timeout as e:
# Convert to Atlas error
raise convert_exception(
e,
error_cls=APIError,
message="LLM API request timed out",
details={"model": model, "timeout": client.timeout},
severity=ErrorSeverity.ERROR
)
except requests.ConnectionError as e:
# Convert to Atlas error
raise convert_exception(
e,
error_cls=APIError,
message="Failed to connect to LLM API",
details={"model": model},
severity=ErrorSeverity.ERROR
)
Safe Resource Management
Using the safe_execute function for operations that need cleanup:
from atlas.core.errors import safe_execute, ResourceError
def process_large_file(file_path):
def _process():
file = open(file_path, 'r')
try:
# Process file
return analyze_content(file)
finally:
# Always close the file
file.close()
# Execute with safety wrapper
return safe_execute(
_process,
default={"status": "error", "results": []},
error_cls=ResourceError,
error_msg=f"Failed to process file: {file_path}"
)
Validation with Field Errors
Creating detailed validation errors with field-specific messages:
from atlas.core.errors import ValidationError
def validate_config(config):
field_errors = {}
# Validate max_tokens
if "max_tokens" in config:
if not isinstance(config["max_tokens"], int) or config["max_tokens"] <= 0:
field_errors["max_tokens"] = ["Max tokens must be a positive integer"]
# Validate model_name
if "model_name" not in config or not config["model_name"]:
field_errors["model_name"] = ["Model name is required"]
elif config["model_name"] not in SUPPORTED_MODELS:
field_errors["model_name"] = [f"Unknown model: {config['model_name']}"]
# Raise error if validation failed
if field_errors:
raise ValidationError(
message="Invalid configuration parameters",
field_errors=field_errors,
severity=ErrorSeverity.WARNING
)
return config
Error Response Serialization
Converting errors to API responses:
from atlas.core.errors import AtlasError, convert_exception
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.exception_handler(AtlasError)
async def atlas_error_handler(request, error: AtlasError):
error_dict = error.to_dict()
status_code = 500
# Map severity to HTTP status code
if error.category == ErrorCategory.VALIDATION:
status_code = 400
elif error.category == ErrorCategory.AUTH:
status_code = 401
elif error.category == ErrorCategory.RESOURCE:
status_code = 429
return JSONResponse(
status_code=status_code,
content={"error": error_dict}
)
@app.get("/query")
async def query_endpoint(q: str):
try:
result = process_query(q)
return {"result": result}
except Exception as e:
# Convert any exception to Atlas error
atlas_error = convert_exception(e)
atlas_error.log() # Log the error
raise atlas_error # Will be caught by exception handler
Error Logging Integration
Atlas errors automatically integrate with Python’s logging system:
from atlas.core.errors import AtlasError, ErrorSeverity
import logging
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Errors automatically use appropriate log levels
info_error = AtlasError("Info message", severity=ErrorSeverity.INFO)
info_error.log() # Uses logging.INFO
warning_error = AtlasError("Warning message", severity=ErrorSeverity.WARNING)
warning_error.log() # Uses logging.WARNING
error_error = AtlasError("Error message", severity=ErrorSeverity.ERROR)
error_error.log() # Uses logging.ERROR with traceback if cause is present
critical_error = AtlasError("Critical message", severity=ErrorSeverity.CRITICAL)
critical_error.log() # Uses logging.CRITICAL with traceback if cause is present
Extending the Error System
You can create custom error types for specific needs:
from atlas.core.errors import AtlasError, ErrorCategory, ErrorSeverity
class DatabaseError(AtlasError):
"""Error related to database operations."""
def __init__(
self,
message: str,
details: Optional[Dict[str, Any]] = None,
cause: Optional[Exception] = None,
severity: ErrorSeverity = ErrorSeverity.ERROR,
query: Optional[str] = None,
):
"""Initialize the error.
Args:
message: The error message.
details: Optional detailed information about the error.
cause: The original exception that caused this error.
severity: Severity level of the error.
query: The database query that caused the error.
"""
details = details or {}
if query:
details["query"] = query
super().__init__(
message=message,
severity=severity,
category=ErrorCategory.DATA,
details=details,
cause=cause,
)
Error Handling Best Practices
Use Specific Error Types: Use the most specific error class for each situation
python# Good - specific error type raise ValidationError("Invalid model name") # Bad - generic error raise AtlasError("Invalid model name")
Include Contextual Details: Provide relevant context in the details dict
python# Good - includes context raise APIError("API request failed", details={"status_code": 404, "endpoint": "/messages"}) # Bad - minimal context raise APIError("API request failed")
Preserve Original Exceptions: Include the original exception as the cause
pythontry: response = requests.get(url, timeout=5) response.raise_for_status() except requests.RequestException as e: raise APIError("Request failed", cause=e)
Log At Appropriate Levels: Match error severity to the actual impact
python# Minor formatting issue - use WARNING raise ValidationError("Invalid date format", severity=ErrorSeverity.WARNING) # Critical authentication failure - use CRITICAL raise AuthenticationError("API key rejected", severity=ErrorSeverity.CRITICAL)
Handle Errors at Appropriate Levels: Catch errors at levels where you can take meaningful action
pythondef api_call(): try: # Low-level API call return make_request() except Exception as e: # Convert to APIError but let caller decide how to handle it raise convert_exception(e, error_cls=APIError) def user_request_handler(): try: # Higher-level function return api_call() except APIError as e: # Handle error appropriately at this level e.log() return {"error": "Service temporarily unavailable"}
Related Documentation
- Configuration System - Documentation for the configuration system
- Environment Variables Module - Documentation for environment variables handling
- Telemetry Module - Documentation for telemetry and logging