Handle database errors in Rust by returning a Result<T, E> from your functions and propagating errors with the ? operator instead of panicking.
use std::error::Error;
use std::fmt;
#[derive(Debug)]
struct DbError(String);
impl fmt::Display for DbError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Database error: {}", self.0)
}
}
impl Error for DbError {}
fn query_db() -> Result<String, DbError> {
// Simulate a database call that might fail
let data = "user_data";
Ok(data.to_string())
}
fn main() {
match query_db() {
Ok(data) => println!("Got data: {}", data),
Err(e) => eprintln!("Failed: {}", e),
}
}
Alternatively, use the ? operator to propagate errors up the call stack:
fn process_data() -> Result<String, DbError> {
let data = query_db()?; // Propagates error if query_db fails
Ok(format!("Processed: {}", data))
}
For async database operations, use async fn and return Result<T, E>:
async fn fetch_user(id: u32) -> Result<String, DbError> {
// Simulate async DB call
Ok(format!("User {}", id))
}
Use a custom error type or a crate like anyhow or thiserror for production-grade error handling.