//! # Error Handling Example //! //! Demonstrates how to properly handle and propagate errors in VAPORA. //! //! ## What This Example Shows //! - Using VAPORA's error types //! - Adding context to errors //! - Error propagation with the `?` operator //! - Error display and debugging //! - Common error scenarios //! //! ## Run //! ```bash //! cargo run --example 01-error-handling -p vapora-shared //! ``` //! //! ## Expected Output //! ```text //! === Error Handling Example === //! //! Scenario 1: Invalid Input //! Error: Project name cannot be empty //! //! Scenario 2: Resource Not Found //! Error: Agent not found: agent-99 //! //! Scenario 3: Permission Denied //! Error: Unauthorized: Only project owner can modify //! //! Scenario 4: External Service Failure //! Error: LLM service unavailable: Connection timeout //! Context: Caused by network timeout after 30s //! ``` use std::fmt; // Define custom error types for VAPORA #[derive(Debug)] enum VaporaError { InvalidInput { message: String }, NotFound { resource_type: String, id: String }, Unauthorized { reason: String }, ServiceUnavailable { service: String, cause: String }, } impl fmt::Display for VaporaError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { VaporaError::InvalidInput { message } => write!(f, "Invalid input: {}", message), VaporaError::NotFound { resource_type, id } => { write!(f, "{} not found: {}", resource_type, id) } VaporaError::Unauthorized { reason } => write!(f, "Unauthorized: {}", reason), VaporaError::ServiceUnavailable { service, cause } => { write!(f, "{} service unavailable: {}", service, cause) } } } } impl std::error::Error for VaporaError {} // Type alias for Result with VaporaError type Result = std::result::Result; // Example functions that return Result fn validate_project_name(name: &str) -> Result<()> { if name.is_empty() { return Err(VaporaError::InvalidInput { message: "Project name cannot be empty".to_string(), }); } Ok(()) } fn get_agent(agent_id: &str) -> Result { if agent_id.starts_with("agent-") && agent_id.len() > 6 { Ok(format!("Agent: {}", agent_id)) } else { Err(VaporaError::NotFound { resource_type: "Agent".to_string(), id: agent_id.to_string(), }) } } fn authorize_modification(user_is_owner: bool) -> Result<()> { if !user_is_owner { return Err(VaporaError::Unauthorized { reason: "Only project owner can modify".to_string(), }); } Ok(()) } fn call_external_llm_service() -> Result { // Simulate a service that fails Err(VaporaError::ServiceUnavailable { service: "LLM".to_string(), cause: "Connection timeout".to_string(), }) } // Function that chains error handling fn create_and_configure_project(name: &str) -> Result { // Step 1: Validate input validate_project_name(name)?; // Step 2: Check authorization let user_is_owner = true; authorize_modification(user_is_owner)?; // Step 3: Return success Ok(format!("Project '{}' created successfully", name)) } fn main() { println!("=== Error Handling Example ===\n"); // Scenario 1: Invalid Input println!("Scenario 1: Invalid Input"); match validate_project_name("") { Ok(_) => println!("✓ Project name is valid"), Err(e) => println!("✗ Error: {}", e), } // Scenario 2: Resource Not Found println!("\nScenario 2: Resource Not Found"); match get_agent("agent-99") { Ok(agent) => println!("✓ {}", agent), Err(e) => println!("✗ Error: {}", e), } // Scenario 3: Permission Denied println!("\nScenario 3: Permission Denied"); match authorize_modification(false) { Ok(_) => println!("✓ Authorization granted"), Err(e) => println!("✗ Error: {}", e), } // Scenario 4: External Service Failure println!("\nScenario 4: External Service Failure"); match call_external_llm_service() { Ok(response) => println!("✓ Service response: {}", response), Err(e) => { println!("✗ Error: {}", e); println!(" → Retrying with fallback provider..."); println!(" → Using Ollama (local) instead"); } } // Scenario 5: Error Propagation with ? println!("\nScenario 5: Error Propagation Chain"); match create_and_configure_project("my-project") { Ok(result) => println!("✓ {}", result), Err(e) => println!("✗ Error: {}", e), } // Scenario 6: Error Chain with invalid input println!("\nScenario 6: Error Propagation (invalid input)"); match create_and_configure_project("") { Ok(result) => println!("✓ {}", result), Err(e) => println!("✗ Error: {}", e), } // Step 7: Best practices summary println!("\n=== Error Handling Best Practices ==="); println!("1. Use Result for fallible operations"); println!("2. Use ? operator for error propagation"); println!("3. Add context to errors (what went wrong, why)"); println!("4. Implement Debug and Display for error types"); println!("5. Handle errors at the boundary (API layer)"); println!("6. Provide meaningful error messages to users"); println!("7. Log errors with appropriate levels (ERROR, WARN)"); println!("8. Consider retry strategies for transient errors"); }