You first have to isolate the areas where errors might occur, and are user-visible. Then you can document them. Its that simple.
Well, simple in theory.. in practice errors can occur all over the damn place, and reporting them can turn nice code into a monster of logging, exception throwing and handling, and passing return values.
I would recommend a 2-step approach then. First is to log, log lots and lots.
Second is to determine the major components and their interfaces, and to define what major error cases these components can find themselves in. You can then log in a more visible manner when one of these errors (how you handle the error internally is up to you - exceptions or error codes make no difference here). A user will generally then see the error and go to the logs for more detailed information.
The same approach is used for web servers and your http error code example. If the user sees a 404, and reports it to support, they will look in the logs for the details of what was going on, which page was visited, when, and will glean any other info they can from where-ever else make sense, be in the DB, the network or the application.