Monadic error handling (such as Rust's) is a good compromise because it allows you to handle errors precisely when you want to _and_ bubble them up with minor boilerplate when you don't. You can even add context without unwrapping the whole thing.
That's why it's often considered one of the better approaches: it has both the "errors as values" benefits (encoding errors in the type system) and avoids many of its problems (verbosity when you just want to bubble up).
That's why it's often considered one of the better approaches: it has both the "errors as values" benefits (encoding errors in the type system) and avoids many of its problems (verbosity when you just want to bubble up).