Post

⛔ Error handling in #rustlang with anyhow and thiserror Error handling in Rust can be a complex topic, especially since a lot of the patterns are different from other languages. Let's explore some basic options and then go deeper into using anyhow and thiserror crates 🧵👇

0️⃣ The evolution from panic to Result Let's explore error handling approaches using a university database with Student and Course structs, and a Database holding students, courses and an enrollments HashMap. Now let's explore 3 implementations for error handling: V1 - Panic V2 - Bool V3 - Result

Version 1 - Naive approach with panic-crashes the whole program on a simple error Version 2 - Returning bool to indicate success/failure but no error details, we know what failed but not why Version 3 - Using Result to return success values and error details, a good compromise and the rust default

1️⃣ Using Anyhow Building on top of this, let's explore how anyhow can help improve our error handling from here. We first switch Result<Student, String> to anyhow::Result<Student> and use the anyhow::anyhow! macro to create errors with messages.

This is already better than the plain result because: - anyhow::Result can hold any error type, not just String - We get better error trait implementations (Display, Debug, etc.) - We can return different error types from the same function - It sets us up to use anyhow's powerful context feature

2️⃣ Anyhow context Let's add new functionality that also validates the student name before adding them to the db. First, we need to import the Context trait and then use .context() to add context to the error returned from validate_name.

You can see in the last error the top level error message is "Failed to add student with id 2" and the cause is "Name cannot be empty". This additional context is super helpful for complex chains of function calls.

We could extend this to a more complex example like course enrollment with a deeper chain. Here's how the process_enrollment function uses context at multiple levels. Notice how each layer of context provides additional info about where in the call stack the error occurred.

3️⃣ Custom error types The course enrollment is a pretty representative complex example, and the solution with anyhow context is normally good enough for internal application code where you don't need to worry about exposing error types to external clients However, if this was a library ...

and we wanted to expose more specific error types that clients can match on and handle differently, we need custom error types. We can use the thiserror::Error derive macro to easily create a custom error enum with different variants for each error case.

Then, we change all instances of anyhow! to return the appropriate EnrollmentError variant, and change the function signatures to return Result<T, EnrollmentError>. Note that we can no longer use `.context()` since that's an anyhow feature, but the errors themselves need to be descriptive enough

The error messages are now cleaner and more structured. With custom error types, library clients can: - Match on specific error variants to handle different cases - Access error fields programmatically (like student_id, course_id) - Make informed decisions based on the error type

💡 This is the key difference: anyhow is great for applications where you just need good error messages, while thiserror is perfect for libraries where consumers need to handle errors programmatically.

0 reposts4 likes

That's it, we looked at how to do basic error handling in rust and then improved it using anyhow for context and thiserror w error types. Hope it helped you learn 1% more Rust today, follow me for more threads like this and subscribe to receive these threads over email forms.gle/vY6zXE21Dkwa... 🦋 🦀

forms.gleRust Threads NewsletterGet bite-size Rust Threads about fundamental concepts and practical usage right in your inbox every Thursday. Checkout this for a sample of previous threads:…