At least to me, this is an anti-pattern in any language that supports try-catch type error handling.
Many levels of try-catch should almost always be eliminated except for a small handful of use cases.
Unless you 1) can recover, 2) can retry, 3) need to log some local context, 4) need to transform the lower level error (including transforming it for display purposes), my heuristic is that it should always be handled at the highest level possible in the stack and just let the exception pass through.
Agreed! I normally just raise exceptions all the way up until the method that called the function that errored, then handle the exception at the highest level. That way, I just get a stack trace if I don't have any handling. But I'm also an amateur, self taught developer who's probably doing most things wrong :p
The point of chaining exceptions is to add information to an error result. It prevents one from having to pass down information to produce an error message that makes sense to the user.
That really falls into "3) need to log some local context" which could be parameters, state, etc.
But generally, for the user, I posit that it should still be handled at the highest level of granularity and the message returned to the user on an error should be similarly high level.
I try to use exception chaining to create a message that is useful for the user
to actually debug the problem (solution-directed error message).
The classic toy case is either getting back "permission denied" or "can not open foo" but not both. Chaining of error messages gives a straightforward mechanism for this.
Then, the high-level text, along with the caused-by messages, is displayed without a stack trace to hopefully give the user enough information to address an issue.
Chaining can be done with explicitly returned errors as well as exceptions. The hard part is actually thinking about "is this use to the end user"
Many levels of try-catch should almost always be eliminated except for a small handful of use cases.
Unless you 1) can recover, 2) can retry, 3) need to log some local context, 4) need to transform the lower level error (including transforming it for display purposes), my heuristic is that it should always be handled at the highest level possible in the stack and just let the exception pass through.