Vexing exceptions are the result of unfortunate design decisions. Vexing exceptions are thrown in a completely non-exceptional circumstance, and therefore must be caught and handled all the time.
The classic example of a vexing exception is Int32.Parse, which throws if you give it a string that cannot be parsed as an integer. But the 99% use case for this method is transforming strings input by the user, which could be any old thing, and therefore it is in no way exceptional for the parse to fail. Worse, there is no way for the caller to determine ahead of time whether their argument is bad without implementing the entire method themselves, in which case they wouldn’t need to be calling it in the first place.
This unfortunate design decision was so vexing that of course the frameworks team implemented TryParse shortly thereafter which does the right thing.
You have to catch vexing exceptions, but doing so is vexing.
Try to never write a library yourself that throws a vexing exception.
Here’s a very interesting read on how to approach exception handling for an application:
I especially love the section about Vexing Exceptions: