Error severity levels for categorization and handling.
ErrorContext
A structured container for error context metadata. This allows errors to carry rich contextual information without cluttering the error message itself.
The foundation exception class providing: - Dual messaging: User-friendly message + optional debug details - Context propagation: Rich contextual metadata via ErrorContext - Serialization: to_dict() and from_dict() for crossing process boundaries - Error chaining: Preserves original exception via cause - Severity levels: Categorization for logging and monitoring - Retry hints: Indicates if error is transient and retryable
Base exception class with rich context and dual messaging.
Example: Basic Usage
# Simple error with just a messageerror1 = BaseError("Configuration file not found")print("User message:", error1.get_user_message())print("Debug message:", error1.get_debug_message())print("Severity:", error1.severity.value)
User message: Configuration file not found
Debug message: Configuration file not found
Severity: error
# Error with debug informationerror2 = BaseError( message="Failed to save settings", debug_info="JSONDecodeError at line 42: Unexpected token '}'", severity=ErrorSeverity.ERROR)print("User message:", error2.get_user_message())print("Debug message:", error2.get_debug_message())
User message: Failed to save settings
Debug message: Failed to save settings | Debug: JSONDecodeError at line 42: Unexpected token '}'
Example: With Context
# Error with rich contextctx = ErrorContext( job_id="job-789", plugin_id="whisper_large", operation="load_model", extra={"model_path": "/models/whisper-large-v3.pt", "gpu_id": 0})error3 = BaseError( message="GPU out of memory", debug_info="CUDA error: out of memory (tried to allocate 8.50 GiB)", context=ctx, severity=ErrorSeverity.CRITICAL, is_retryable=False)print("Error:", error3)print("\nContext:", error3.context.to_dict())print("\nRetryable:", error3.is_retryable)
# Simulate catching and re-raising with contexttry:# Simulate an original errorraiseFileNotFoundError("/models/config.json")exceptFileNotFoundErroras e:# Wrap with our error type error4 = BaseError( message="Plugin configuration not found", debug_info="Check that the model was downloaded correctly", context=ErrorContext(plugin_id="whisper_base", operation="load_config"), cause=e )print("User message:", error4.get_user_message())print("Debug message:", error4.get_debug_message())print("\nOriginal cause:", error4.cause)
User message: Plugin configuration not found
Debug message: Plugin configuration not found | Debug: Check that the model was downloaded correctly | Caused by: FileNotFoundError: /models/config.json
Original cause: /models/config.json
Example: Serialization (for Worker Processes)
import json# Create an errorerror5 = BaseError( message="Job failed", debug_info="Worker process terminated unexpectedly", context=ErrorContext( job_id="job-999", worker_pid=54321, operation="transcribe" ), severity=ErrorSeverity.ERROR, is_retryable=True)# Serialize to dicterror_dict = error5.to_dict()print("Serialized:")print(json.dumps(error_dict, indent=2))
def risky_operation(should_fail=True):"""Simulated operation that may fail."""if should_fail:raise BaseError( message="Operation failed", debug_info="Insufficient permissions to write to /var/log", context=ErrorContext(operation="write_logs"), is_retryable=False )return"Success!"# Catching the errortry: result = risky_operation(should_fail=True)except BaseError as e:print(f"Caught error: {e.get_user_message()}")print(f"Can retry: {e.is_retryable}")print(f"Severity: {e.severity.value}")# In a real app, you might:# - Log the debug message: logger.error(e.get_debug_message())# - Show user the user message: display_alert(e.get_user_message())# - Send to monitoring: send_to_sentry(e.to_dict())
Caught error: Operation failed
Can retry: False
Severity: error