TLDR; This problem has been solved for 40 years but the software development industry is still very fashion-oriented.
In both Common Lisp and Smalltalk error handlers can resume the computation that raised it, restart it, or refuse to handle it while the error handling code itself can be separated out from where it is caught i.e. into re-usable functions. Without unwinding the stack and losing the context of why/where the error occurred.
This is light years beyond mainstream languages where easy to implement for language creators is almost always prioritized over easy, flexible and powerful error-handling for language users.
Rust, a language that I use on a daily basis professionally still doesn’t have the error handling story down. I expect this from all the usual blub lang suspects but the Rust community seemed to be going for a higher bar, no luck though it seems.
There may be some hope on this front as at least one person on the core team seems to care about this. https://www.ncameron.org/blog/rust-in-2020-one-more-thing
Apologies to C.A.R Hoare for unintentionally stealing half the title of this post from his 1980 ACM Turing Award Lecture.