In this lesson, you will learn how to unify errors originating from multiple concurrent tasks into a single, manageable result.
The Challenge of Parallel Errors
When you run tasks concurrently—such as fetching data from three different APIs simultaneously using tokio::spawn—each task might fail independently. If you simply use the ? operator on individual handles, you only see the first error that bubbles up, potentially losing visibility into the others. To build robust systems, you need a way to collect these disparate failures into a single structure that represents the "combined" outcome of your operation.
Aggregating Results
The idiomatic approach to this is to define a custom error type that can hold multiple source errors. Instead of returning a simple Result<T, MyError>, you might return a Result<T, Vec<MyError>> or a custom CombinedError struct.
Consider a scenario where you launch two tasks:
async fn run_tasks() -> Result<(), Vec<String>> {
let handle1 = tokio::spawn(async { Err("Database failed".to_string()) });
let handle2 = tokio::spawn(async { Err("Network timeout".to_string()) });
let mut errors = Vec::new();
// Join handles and inspect results
for handle in vec![handle1, handle2] {
if let Ok(Err(e)) = handle.await {
errors.push(e);
}
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
In this pattern, we don't return early with ?. Instead, we intentionally wait for all concurrent tasks to finish, inspect their individual outcomes, and push any errors we encounter into a collection. By the end, we decide if the operation was a total success or a partial/total failure based on the contents of that collection.
Why This Matters
By composing these errors, you move from "failing at the first sign of trouble" to "reporting on the total state of the system." This is critical for batch processing or UI-driven requests where the user needs to know exactly which parts of a request failed, rather than just seeing a generic error message.
Key Takeaway: To compose errors from concurrent tasks, collect individual failure results into a container rather than using the ? operator, allowing you to report all issues at once.