Obviously you should be converting exceptions that leave your library into other areas, but internally? Converting exceptions over and over and over again just means losing information from those exceptions, or worse hiding them. If I'm forced to dump a stack-trace to the text file, I want the exact exception that caused the problem, not some vague "Operation Exception" that quintuply wraps my actual desired exception, or worse completely threw it out to "cleaned it up for me" and tells me nothing about what went wrong.
I just helped a teammate work through a bug the other day where somebody decided to "handle" a case-sensitivity problem in their home-brewed SqlLite data-access code by simply returning null for the data member if you got the wrong case. This resulted in improperly-cased column names producing objects with null members - no error happened because they were valid SQL queries, but the dictionary-reading code was silently failing when it was reading the result-set. If the program had just blown up when there was a miss on the dictionary of column names? We would've quickly found out about that stupid case-sensitivity.
Defensive coding just means your bugs go non-local and become data problems instead of exceptions.
That doesn't make any sense. Defensive coding means not silently discarding errors (by returning null, in this case), and has nothing at all to do with exceptions.
As for rewrapping errors, yes, each subsystem should have its own error space. You don't lose data by nesting errors; on the contrary, each level can add additional context to an error result that makes debugging an unexpected issue far easier.
I just helped a teammate work through a bug the other day where somebody decided to "handle" a case-sensitivity problem in their home-brewed SqlLite data-access code by simply returning null for the data member if you got the wrong case. This resulted in improperly-cased column names producing objects with null members - no error happened because they were valid SQL queries, but the dictionary-reading code was silently failing when it was reading the result-set. If the program had just blown up when there was a miss on the dictionary of column names? We would've quickly found out about that stupid case-sensitivity.
Defensive coding just means your bugs go non-local and become data problems instead of exceptions.