Course contentsShow
← Rust
Lesson 888 of 1,9107. Error Handling PatternsFree lesson

Managing Transient vs Fatal Errors

Categorize failure classes based on their potential for automatic correction.

In this lesson, you will learn how to distinguish between errors that resolve themselves through repetition and those that indicate a terminal state for your application.

When building resilient systems, not all errors are created equal. We classify them into two buckets: Transient and Fatal.

Transient Errors

Transient errors are temporary failures—a network hiccup, a database timeout, or a locked file—that likely won’t exist a few milliseconds later. In Rust, these are your primary candidates for retry logic and exponential backoff. Because these errors are external to your application’s core logic, they do not invalidate the system state.

Fatal Errors

Fatal errors signify a violation of your application’s invariants, such as an invalid configuration file, a corrupted database schema, or an exhausted resource that cannot be recovered without human intervention or a hard restart. If you attempt to retry a fatal error, you risk wasting compute cycles or, worse, worsening the system's state.

Consider this categorical split in your error handling:

enum AppError {
    NetworkTimeout,     // Transient: Retryable
    DatabaseUnavailable, // Transient: Retryable
    InvalidConfig,      // Fatal: Stop immediately
    LogicCorruption,    // Fatal: Panic or graceful shutdown
}

fn handle_error(err: AppError) {
    match err {
        AppError::NetworkTimeout | AppError::DatabaseUnavailable => {
            // Trigger Exponential Backoff
            retry_operation();
        }
        AppError::InvalidConfig | AppError::LogicCorruption => {
            // Log as critical and terminate
            terminate_process();
        }
    }
}

The Diagnostic Strategy

The key to management is classification at the boundary. When your functions return Result<T, E>, force yourself to categorize the error as soon as it crosses your service boundary. If you treat a LogicCorruption error as Transient, your system will attempt to "retry" a state that is fundamentally broken, leading to silent failures or "zombie" processes. Conversely, treating a NetworkTimeout as Fatal makes your system fragile and prone to unnecessary downtime.

By strictly separating your retry loops from your shutdown sequences, you ensure that your system remains robust against external noise while staying safe from internal failures.

Key Takeaway: Categorize errors by their solvability; if it can be fixed by waiting, it is transient; if it requires a change in state or logic, it is fatal.