At my last company I had a global variable containing the current error message (much like errno, only a descriptive string rather than an integer). Whenever an error was detected, I would set it to an appropriate message and return -1. A caller would detect the failure and print out the global error descriptor. (This was in C, btw.)
in reply to Useless/Interesting Error Messages
When running under the debugger, it was useful to have an easily recognizable value that would indicate that no error had happened yet, so I initialized it to "Life is good".
Unsurprisingly, I ended up with a number of routines that didn't bother to set the error message, but still returned -1. So it became fairly common to see messages like:
Fatal error, unable to continue: Life is good