For this case, I actually think Python's approach is the best:
- Exceptions, so you don't need error handling
- stack traces so you know the entire call tree. This is pretty important -- without stack traces, it is very hard to make sense of error messages like "Cannot open file 'none'" -- the filename is clearly wrong, but where did this come from.
- chained exceptions so you can add context trivially. Doing "try: ... except: raise Exception('Cannot load config')" will print both error messages and two stack traces, so you know both original error and better description.
- verbose by default so if you don't put any effort into error handling, you get lots of details. This is somewhat controversial -- when some people see large stack traces their eyes glaze over and they just stop reading. But as a program's author, I love this -- the stack traces are informative enough I can often figure out what's wrong immediately.
- Exceptions, so you don't need error handling
- stack traces so you know the entire call tree. This is pretty important -- without stack traces, it is very hard to make sense of error messages like "Cannot open file 'none'" -- the filename is clearly wrong, but where did this come from.
- chained exceptions so you can add context trivially. Doing "try: ... except: raise Exception('Cannot load config')" will print both error messages and two stack traces, so you know both original error and better description.
- verbose by default so if you don't put any effort into error handling, you get lots of details. This is somewhat controversial -- when some people see large stack traces their eyes glaze over and they just stop reading. But as a program's author, I love this -- the stack traces are informative enough I can often figure out what's wrong immediately.