What I remember is the “deep interfaces” advice, which is great. It encourages small surfaces but deep implementations. Hiding the potentially large list of raisable exceptions helps in keeping an interface or API small. Errors are handled transparently and the user only needs to deal with those they know how to handle. What good is it to raise a deep error that by the time it reaches the top levels (like a web servers middleware loop), it can no longer be handled reasonably and has to be thrown? That’s why, if you can handle it, do so ASAP.
That’s what I remember from that book. Again, perhaps I’m misremembering.
There are exceptions that are a normal result of some function call, and they can be handled by the caller.
But most exceptions are of the kind that you want to pass to some general error reporting thing far away.
This agrees with my intuition, that error codes are most fragile when they must be checked and re-raised across many scopes.