Most advice concerning error handling boils down to a handful of tips and tricks (see this post for example). These hints are helpful but I think they don\'t answer all question
My two cents.
How to decide if an error should be handled locally or propagated to higher level code? Handle errors you can handle. Let errors propagate that you can not.
How to decide between logging an error, or showing it as an error message to the user? Two orthogonal issues, which are not mutually exclusive. Logging the error is ultimately for you, the developer. If you would be interested in it, log it. Show it to the user if it is actionable to the user ("Error: No network connection!").
Is logging something that should only be done in application code? Or is it ok to do some logging from library code. I see no reason why libraries can't log.
In case of exceptions, where should you generally catch them? In low-level or higher level code? You should catch them where you can handle them (insert your definition of handle). If you can't handle them, ignore them (maybe someone up the stack can handle them..).
You certainly shouldn't put a try/catch block around each and every throwing function you call.
Similar question: at what point should you stop propagating an error and deal with it? Should you strive for a unified error handling strategy through all layers of code, or try to develop a system that can adapt itself to a variety of error handling strategies (in order to be able to deal with errors from 3rd party libraries). At the first point that you can actually deal with it. That point may not exist, and your app may crash. Then you'll get a nice crash dump, and can update your error handling.
Does it make sense to create a list of error codes? Or is that old fashioned these days? Another point of contention. I'd actually say no: one super list of all error codes implies that that list is always up to date, so you can actually do harm when it's not up to date. It's better to have each function document all the error codes it can return, rather than have one super list.
The first question is probably what can you do about the error?
Can you fix it (in which case do you need to tell the user) or can the user fix it?
If nobody can fix it and you are going to exit, is there any value in having this reported back to you (through a crash dump or error code)?