Okay hear me out:
I don't like exception handling, because it doesn't feel "pure" and consistent with the rest of my program flow. If any errors happen, I want to know what they are so I can plan ahead. You might say "well, just catch your exceptions dammit". But see, what if I forget to catch an exception right away and it propagates? Also, other than Swift, I don't know of any programming language that let's me explicitly mention if a function could throw an exception. In Python, for example, you can't just do Optional[str], because returning None is different from raising an exception. So by just looking at a function type signature, one can't know if it throws, which means you never know if you should use try/catch or not.
But let's say you take care of all edge cases and return None in those bad paths instead of raising exceptions. Let's also assume that Python does't suck and it never raises exceptions by its own standard libraries (e.g., json throws). The problem is: How do we know if the function returned None because the evaluation was None, or because it failed at some point?
So a better approach is to explicitly say the function returns "something" which may or may not be there. If it's there, then the function worked correctly, even if the value is None. If it's not there, then the function failed. Go does this. Rust does this better. Haskell has had this since ages thanks to Monads.
I like to think of monads as wrappers around data. In Python, I simply write a Result monad (similar to Rust). In Haskell, this is called a Maybe monad.