I think there’s room for both. Haskell lets you do both. Failures as return values is nice in some cases like parsers and whatnot. Failures as exceptions is nice when you’ve got a load of I/O based code that can fail in myriad ways and you don’t care to enumerate them nor would benefit in doing so.
At first I liked Rust’s angle until I saw people using it at work and saw that it’s actually an inconvenience: people sprinkle “anyhow” everywhere as a way to avoid having to produce a well typed error, and every function is littered with “?” on almost every line to the point of meaninglessness. Java has checked exceptions, and not everybody is too happy about them.
Haskell lets you be blasé like Erlang (throw and forget) or meticulous like Java/Rust, depending on your discretion. It’s not perfect but I feel lucky to have it.
MzScheme differentiated exceptions from termination of a thread by a custodian (Custodians) that couldn’t be stopped, IIRC. That was really neat. And Common Lisp folk use restarts (Beyond Exception Handling: Conditions and Restarts) all the time to provide a developer experience, which is another island of behavior quite far away from Haskell/Rust.