Instruction file imported from charliemic/electric-sheep (
.cursor/rules/error-handling.mdc). Copyright stays with the author.
Error Handling Principles
Error Handling Requirements
When implementing features:
- ✅ Handle errors gracefully without crashing
- ✅ Provide user-friendly error messages
- ✅ Log errors with sufficient context
- ✅ Use appropriate error types
- ✅ Follow error conversion strategies
- ✅ REQUIRED: Use
Result<T>for operations that can fail - ✅ REQUIRED: Use
NetworkError.fromException()for network errors
Error Handling Principles
Fail Fast
- ✅ Detect errors as early as possible
- ✅ Validate input before processing
- ✅ Check preconditions before operations
Graceful Degradation
- ✅ Handle errors without crashing
- ✅ Provide fallback behavior when possible
- ✅ Show user-friendly error messages
- ✅ Allow users to recover from errors
Error Types
- ✅ Use specific error types (validation, network, system, etc.)
- ✅ Convert between error types appropriately
- ✅ Follow Error Conversion Strategies
Error Handling Patterns
Result Pattern (REQUIRED for Operations That Can Fail)
CRITICAL: ALWAYS use Result<T> for operations that can fail (network, database, file I/O, etc.)
// Good: Use Result type for operations that can fail
suspend fun loadData(): Result<Data> {
return try {
val data = apiService.getData()
Result.success(data)
} catch (e: Exception) {
val networkError = NetworkError.fromException(e)
networkError.log("ApiService", "Failed to load data")
Result.failure(networkError)
}
}
When to use Result:
- ✅ Network operations (API calls, remote data fetching)
- ✅ Database operations (queries, inserts, updates)
- ✅ File I/O operations
- ✅ Any operation that can fail and needs error handling
When NOT to use Result:
- ❌ Pure functions with no side effects (use exceptions for validation errors)
- ❌ Internal helper functions that are always called within try-catch
- ❌ Operations that should crash the app if they fail (use exceptions)
Network Error Handling (REQUIRED)
CRITICAL: ALWAYS use NetworkError.fromException() for network-related errors
// Good: Convert exceptions to NetworkError using fromException()
suspend fun fetchData(): Result<Data> {
return try {
val data = apiService.getData()
Result.success(data)
} catch (e: Exception) {
// ALWAYS use NetworkError.fromException() for network errors
val networkError = NetworkError.fromException(e)
networkError.log("ApiService", "Failed to fetch data")
Result.failure(networkError)
}
}
DO NOT:
- ❌ Throw raw
IOExceptionorExceptionfrom network operations - ❌ Create
NetworkErrormanually without usingfromException() - ❌ Use generic error types when
NetworkErroris appropriate
Exception Handling (for non-network operations)
// Good: Specific error handling with logging for non-network operations
try {
val result = localOperation()
return Success(result)
} catch (e: ValidationException) {
Logger.warn("Validation", "Validation failed", e)
return Error("Invalid input: ${e.message}")
} catch (e: Exception) {
Logger.error("Service", "Unexpected error", e)
return Error("An unexpected error occurred")
}
Logging Errors
Log Levels for Errors
- ERROR: Exceptions, failures, unrecoverable conditions
- WARN: Recoverable errors, fallback scenarios
- INFO: Important flow events, successful operations
Error Logging
// Good: Log errors with context
try {
val result = operation()
} catch (e: Exception) {
Logger.error("ComponentName", "Operation failed: context", e)
// Handle error
}
User-Facing Error Messages
DO ✅
- Provide clear, actionable error messages
- Explain what went wrong
- Suggest how to fix the issue
- Use user-friendly language
DON'T ❌
- Don't expose technical details to users
- Don't leak sensitive information
- Don't use technical jargon
- Don't blame the user
Related Documentation
AI_AGENT_GUIDELINES.md- Complete error handling guidelinesdocs/architecture/ERROR_HANDLING.md- Error handling architecturedocs/architecture/ERROR_CONVERSION_STRATEGIES.md- Error conversion strategies