I’ve steadily been concluding that, in a vacuum, result-based errors are vastly superior to exceptions for potentially-recoverable errors, but that you absolutely require static typing before the ergonomics become acceptable.
One important thing to also realise is that result-based errors aren’t actually incompatible with stack traces, chaining or being verbose by default, though Rust chose to eschew those features in its standard library, because it wasn’t clear (and still isn’t) exactly how it’s best to do that, especially if you’re trying to minimise cost, which a language like Rust is. That’s why there are so many experiments, such as anyhow.
Result-based errors is also excellent at some forms of composition that exceptions are completely useless for; for example, in Rust an iterator can yield results, and most file system stuff does that, so you can use things like map, filter, &c. on the iterator—you can even collect `impl Iterator<Item=Result<T, E>>` to `Result<Vec<T>, E>`, easy early return semantics. Anything like this is not at all elegant in Python.