7.6 KiB
| summary | read_when | ||
|---|---|---|---|
| Review Peekaboo Error Handling Guide guidance |
|
Peekaboo Error Handling Guide
This guide describes the unified error handling system in PeekabooCore, designed to provide consistent, user-friendly error messages across all services.
Overview
The error handling system consists of three main components:
- Standardized Errors - Consistent error types and codes
- Error Formatting - Unified presentation for CLI, JSON, and logs
- Error Recovery - Automatic retry and graceful degradation
Error Types
Standard Error Codes
All errors in Peekaboo use standardized error codes for consistency:
// Permission errors
case screenRecordingPermissionDenied = "PERMISSION_DENIED_SCREEN_RECORDING"
case accessibilityPermissionDenied = "PERMISSION_DENIED_ACCESSIBILITY"
// Not found errors
case applicationNotFound = "APP_NOT_FOUND"
case windowNotFound = "WINDOW_NOT_FOUND"
case elementNotFound = "ELEMENT_NOT_FOUND"
// Operation errors
case captureFailed = "CAPTURE_FAILED"
case interactionFailed = "INTERACTION_FAILED"
case timeout = "TIMEOUT"
Error Categories
Errors are grouped into categories:
- Permission: Access control issues
- Not Found: Missing resources
- Operation: Execution failures
- Validation: Input errors
- System: Infrastructure issues
- AI: AI provider problems
Using the Error System
Creating Errors
Use the predefined error types for consistency:
// Permission errors
throw PermissionError.screenRecording()
throw PermissionError.accessibility()
// Not found errors
throw NotFoundError.application("Safari")
throw NotFoundError.window(app: "Finder", index: 2)
throw NotFoundError.element("Submit button")
// Operation errors
throw OperationError.captureFailed(reason: "Display disconnected")
throw OperationError.timeout(operation: "screenshot", duration: 30)
// Validation errors
throw ValidationError.invalidInput(field: "coordinates", reason: "Outside screen bounds")
throw ValidationError.ambiguousAppIdentifier("Safari", matches: ["Safari", "Safari Technology Preview"])
Formatting Errors
Use ErrorFormatter for consistent presentation:
// For CLI output
let message = ErrorFormatter.formatForCLI(error, verbose: true)
// For JSON responses
let json = ErrorFormatter.formatForJSON(error)
// For logging
let logMessage = ErrorFormatter.formatForLog(error)
// For multiple errors
let summary = ErrorFormatter.formatMultipleErrors(errors)
Error Recovery
Retry Policies
Configure automatic retry behavior:
// Use standard retry policy (3 attempts, exponential backoff)
let result = try await RetryHandler.withRetry {
try await captureScreen()
}
// Custom retry policy
let policy = RetryPolicy(
maxAttempts: 5,
initialDelay: 0.1,
delayMultiplier: 2.0,
retryableErrors: [.timeout, .captureFailed]
)
let result = try await RetryHandler.withRetry(policy: policy) {
try await performOperation()
}
Recovery Suggestions
Errors include recovery suggestions:
let error = PermissionError.screenRecording()
if let suggestion = error.recoverySuggestion {
print("Suggestion: \(suggestion)")
// Output: "Grant Screen Recording permission in System Settings"
}
Graceful Degradation
Handle partial failures:
let options = DegradationOptions(
allowPartialResults: true,
fallbackToDefaults: true,
skipNonCritical: true
)
// Operations can return degraded results
let result = DegradedResult(
value: partialData,
errors: [minorError],
warnings: ["Some features unavailable"],
isPartial: true
)
Service Integration
Example: ScreenCaptureService
public func captureScreen(displayIndex: Int? = nil) async throws -> CaptureResult {
// Check permissions
guard hasScreenRecordingPermission() else {
throw PermissionError.screenRecording()
}
// Validate input
if let index = displayIndex, index < 0 || index >= screenCount {
throw ValidationError.invalidInput(
field: "displayIndex",
reason: "Must be between 0 and \(screenCount - 1)"
)
}
// Perform capture with retry
return try await RetryHandler.withRetry(policy: .standard) {
guard let image = performCapture() else {
throw OperationError.captureFailed(
reason: "Unable to capture display"
)
}
return CaptureResult(image: image)
}
}
CLI Integration
Error Output
The CLI automatically formats errors based on output mode:
# Normal mode - user-friendly message
$ peekaboo capture
Error: Screen Recording permission is required. Please grant permission in System Settings > Privacy & Security > Screen Recording.
Suggestion: Grant Screen Recording permission in System Settings
# Verbose mode - includes context
$ peekaboo capture --verbose
Error: Screen Recording permission is required...
Suggestion: Grant Screen Recording permission in System Settings
Context:
permission: screen_recording
# JSON mode - structured output
$ peekaboo capture --json
{
"success": false,
"error": {
"error_code": "PERMISSION_DENIED_SCREEN_RECORDING",
"message": "Screen Recording permission is required...",
"recovery_suggestion": "Grant Screen Recording permission in System Settings",
"context": {
"permission": "screen_recording"
}
}
}
Best Practices
1. Use Standardized Errors
Always use the predefined error types instead of creating custom errors:
// ✅ Good
throw NotFoundError.application("TextEdit")
// ❌ Avoid
throw NSError(domain: "PeekabooError", code: 404, userInfo: nil)
2. Provide Context
Include relevant context in errors:
throw ValidationError.invalidCoordinates(x: 5000, y: 3000)
// Error includes the invalid coordinates in context
3. Use Appropriate Retry Policies
Choose retry policies based on operation type:
// Network operations - aggressive retry
RetryPolicy.aggressive
// User interactions - conservative retry
RetryPolicy.conservative
// Critical operations - no retry
RetryPolicy.noRetry
4. Handle Degraded Results
Design services to continue with partial data when appropriate:
// Allow partial window list if some windows fail
let windows = await collectWindows(options: .lenient)
if windows.isPartial {
logger.warning("Some windows could not be accessed")
}
Migration Guide
To migrate existing error handling:
- Replace custom errors with standardized types
- Update error formatting to use
ErrorFormatter - Add retry logic where appropriate
- Implement recovery suggestions
Example migration:
// Before
throw NSError(domain: "Peekaboo", code: 1, userInfo: [
NSLocalizedDescriptionKey: "App not found"
])
// After
throw NotFoundError.application(appName)
Testing Errors
Test error handling comprehensively:
@Test
func testPermissionError() async throws {
let error = PermissionError.screenRecording()
#expect(error.code == .screenRecordingPermissionDenied)
#expect(error.userMessage.contains("Screen Recording"))
#expect(error.recoverySuggestion \!= nil)
let json = ErrorFormatter.formatForJSON(error)
#expect(json["error_code"] as? String == "PERMISSION_DENIED_SCREEN_RECORDING")
}
Future Enhancements
Planned improvements:
- Localization support for error messages
- Error analytics and reporting
- Advanced recovery strategies
- Error aggregation for batch operations EOF < /dev/null