Earlier quoted context omitted.
This is error-prone boilerplate that obscures the code, obscures the logs and is a known antipattern (log and throw) - which you're implementing manually, by hand, in the hope you never make a mistake. You shouldn't do manually what you can automate. Boilerplate can make you feel productive and can give you warm fuzzies inside when you see lots of patterns that look familiar, but seeing the same patterns over and ove…
No. If you want to have the same information without that approach, you need to implement nested levels of error information, ten layers deep, each layer having a diagnostic, a log level, and file, line information, and a reason. In other words, you are building your own custom stack trace object, with annotated diagnostics. In addition, you can't reason about this at the upper level anyway, or you are rebuilding you…
If there's extra information you need to know about what's going on, you probably want to log it in non-error cases too, because it'll contextualize an error before the error occurs. You can't log on unwind for decisions made in routines that were invoked and returned from, and are no longer on the stack, in the error case.
> Why is it error-prune. You receive an error of one type and need to convert it into an error of another type. You need to handle that or the compiler will bark.
This is a choice you've made, not something inherent to unchecked exceptions. My argument is that you should not generally change the type of the error, and let polymorphism cover the abstraction. It's error prone because it's code you need to write. All code you write is on the cost side of the ledger and liable to contain mistakes.
> How does it obscure the logs?
You get lots of error log messages for a single error.
> In addition, you would need to allocate on a failure path, which sounds like a nightmare.
I wanted to address this separately. Allocating on the failure path is only a real problem in OOM or severe memory corruption scenarios, in which case logging may not be available and the best course of action is probably to abort the program. In this case, you want the logs that led up to the abort, rather than trying to log positively under severe memory conditions.
Are you a Go user by any chance? I've stayed away from Go precisely because of its boilerplate-reliant error handling mechanism. Or if you're stuck with C++ (with or without exceptions), my commiserations.