>> and we all intend to put that try…catch block in place. Really, we do. But it’s not always obvious where it should go. And it’s all too easy to forget one. And before you know it, your application crashes.
Actually this is a good thing, it encourages you to make your code into hierarchical, tree-like structures. Then you have a try-catch at the root of each tree. Some apps have only one root (e.g. the program's entry point), others have a few (e.g. API endpoints on the server); it depends on how many kinds of parallel/async workloads your system has to handle but generally this should be obvious; if your system's entry points are not obvious to the point that you can 'forget' to wrap try-catch blocks around them, it's typically the sign of a bigger architectural design flaw.
>> Another thing to think about is that exceptions make our code impure. Why functional purity is a good thing is a whole other discussion.
Yes, it's a whole other discussion in which many developers might take an opposing stance. Personally, I think that co-locating state and logic is key to achieving modularity and clear separation of concerns; OOP is likely the best way to achieve that. I do think that functional purity is good in some cases, but not the majority of cases.
A lot of the large functional systems that I've seen were highly deterministic, highly robust spaghetti code; they are difficult to make sense of and can become impossible to maintain.