You can use the ? operator in main
For longer than I want to admit, my Rust main functions were littered with .unwrap() and .expect() on setup code, because I thought ? only worked in functions that returned Result. It does. And main can return Result.
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = std::fs::read_to_string("config.toml")?;
let parsed: Config = toml::from_str(&config)?;
run(parsed)?;
Ok(())
}
If main returns Err, the program prints the Debug representation of the error and exits with a non-zero status. That is exactly what you want for a CLI or a service bootstrap. No panic, no stack trace noise, just the error and a clean failure code.
Box<dyn Error> is enough to get started because every error type that implements Error converts into it automatically through ?. Later you can swap in anyhow::Result for nicer context messages. But the unlock was realizing main is not a special place where you have to panic. It is just a function, and it can propagate.