Exceptions – Why Many Exception Messages Lack Useful Details

cc++-cliexceptionslanguage-agnostic

It seems there is a certain amount of agreement that exception messages should contain useful details.

Why is it that many common exceptions from system components do not contain useful details?

A few examples:

  • .NET List index access ArgumentOutOfRangeException does not tell me the index value that was tried and was invalid, nor does it tell me the allowed range.
  • Basically all exception messages from the MSVC C++ standard library are utterly useless (in the same vein as above).
  • Oracle exceptions in .NET, telling you (paraphrased) "TABLE OR VIEW not found", but not which one.

So, to me it seems that for the most part exception messages do not contain sufficient details to be useful. Are my expectations out of line? Am I using exceptions wrong that I even notice this? Or maybe my impression is wrong: a majority of exceptions do actually provide useful details?

Best Answer

Exceptions do not contain useful details because the concept of exceptions has not matured yet enough within the software engineering discipline, so many programmers do not understand them fully, and therefore they do not treat them properly.

Yes, IndexOutOfRangeException should contain the precise index that was out of range, as well as the range that was valid at the time that it was thrown, and it is contemptible on behalf of the creators of the .NET runtime that it doesn't. Yes, Oracle's table or view not found exception should contain the name of the table or view that was not found, and again, the fact that it does not is contemptible on behalf of whoever is responsible for this.

To a large part, the confusion stems from the misguided original idea that exceptions should contain human-readable messages, which in turn stems from a lack of understanding of what exceptions are all about, so it is a vicious cycle.

Since people think that the exception should contain a human-readable message, they believe that whatever information is carried by the exception should also be formatted into the human-readable message, and then they are either bored to write all the human-readable message-building code, or they are afraid that doing so might be divulging an inadvisable amount of information to whatever prying eyes might see the message. (The security issues mentioned by other answers.)

But the truth of the matter is that they should not be worrying about that because the exception should not contain a human-readable message. Exceptions are things that only programmers should ever see and/or deal with. If there is ever a need to present failure information to a user, that has to be done at a very high level, in a sophisticated manner, and in the user's language, which, statistically speaking, is unlikely to be English.

So, for us programmers, the "message" of the exception is the class name of the exception, and whatever other information is pertinent to the exception should be copied into (final/readonly) member variables of the exception object. Preferably, every single conceivable little bit of it. This way, no message needs to (or should) be generated, and therefore no prying eyes can see it.

To address the concern expressed by Thomas Owens in a comment below:

Yes, of course, at some level, you will create a log message regarding the exception. But you already see the problem with what you are saying: on one hand, an exception log message without a stack trace is useless, but on the other hand, you don't want to let the user see the entire exception stack trace. Again, our problem here is that our perspective is skewed by traditional practices. Log files have traditionally been in plain text, which may have been fine while our discipline was in its infancy, but perhaps not any more: if there is a security concern, then the log file must be binary and/or encrypted.

Whether binary or plain text, the log file should be thought of as a stream into which the application serializes debug information. Such a stream would be for the programmers' eyes only, and the task of generating debugging information for an exception should be as simple as serializing the exception into the debug log stream. This way, by looking at the log you get to see the exception class name, (which, as I have already stated, is for all practical purposes "the message",) each of the exception member variables which describe everything which is pertinent-and-practical-to-include-in-a-log, and the entire stack trace. Note how the formatting of a human-readable exception message is conspicuously missing from this process.

P.S.

A few more of my thoughts on this subject can be found in this answer: How to write a good exception message

P.P.S.

It appears that a lot of people were being ticked off by my suggestion about binary log files, so I amended the answer once again to make it even more clear that what I am suggesting here is not that the log file should be binary, but that the log file may be binary, if need be.