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?

  • 58
    It should be noted that from the side of security professionals, "error messages should contain no details about the internals of the system" is a rule of thumb. – Telastyn Apr 13 '15 at 14:23
  • 118
    @Telastyn: Only if your system is open to attackers. If you're running a Web server, for example, you want to serve up bland error messages to the end-user, but you still want very detailed error messages to get logged at your end. And on client-side software, where the user is not an attacker, you definitely want those error messages to be as detailed as possible, so that when something goes wrong and you get sent a bug report, you have as much information to work with as possible, because a lot of times that's all you get. – Mason Wheeler Apr 13 '15 at 14:27
  • 9
    @Snowman: What's inaccessible to the user if it's client-side software? The owner of the machine owns the machine and can get at anything. – Mason Wheeler Apr 13 '15 at 14:42
  • 14
    Related reading: How to write a good exception message and What is the proper response to lousy error message? – user22815 Apr 13 '15 at 15:10
  • 6
    There's always some additional info that you would like to have. I find the messages that you give as examples to be quite good. You can debug the problem with them. Far better than "error 0x80001234" (example inspired by Windows Update). – usr Apr 13 '15 at 17:04
up vote 202 down vote accepted

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.

  • 4
    I've looked over some of the exception classes in the .NET Framework, and it turns out there are plenty of opportunities for adding this kind of information programmatically. So I guess the question resolves to "why don't they." But +1 for the whole "human-readable" thing. – Robert Harvey Apr 13 '15 at 16:18
  • 7
    I don't agree that exceptions shouldn't contain a human-readable component. At some level, you may want to create a log message regarding the exception. I'd argue that logging a stack trace to a user-readable log file is exposing implementation details that you don't want to expose, so the human readable message should be logged. When presented with the log file that contains the error, developers should have a starting point to begin their debugging and be able to force the exception to happen. The human-readable component should be appropriately detailed without giving away implementation. – Thomas Owens Apr 13 '15 at 16:20
  • 44
    so programmer's aren't human? Looking at my colleagues this confirms some suspicions I've had for some time... – gbjbaanb Apr 13 '15 at 16:22
  • 51
    Again, there's nothing wrong with letting the user see the entire stack trace, as long as the software is client-side. Every professional software project I've ever worked on, and most of the amateur ones as well, contained a logging system that would generate a full error dump when an unhandled exception was raised, including full stack traces of all currently-running threads in the process. And the user could (gasp, oh horror!) look at it any time he wanted, since that is necessary (not simply useful, but required) in order to send the error message back to us! What is wrong with that? – Mason Wheeler Apr 13 '15 at 18:31
  • 13
    I'm also not convinced with respect to binary-only log files. Mainly because of my experience with systemd. Its special tool for viewing these logs is quite confusing and appears to have been designed by a committee of Shakespeare's monkeys. Consider that, for a web application, the first person to see your exception is often going to be the sysadmin, and he is going to want to determine if it's something he needs to fix (e.g. the disk ran out of space) or pass back to the developers. – Michael Hampton Apr 14 '15 at 4:52

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

In my experience, there are a number of reasons that exceptions do not contain useful information. I expect that these sorts of reasons would also apply to system components - but I don't know for sure.

  • Security focused people see exceptions as a source of information leakage (for example). Since the default behavior of exceptions is to display that information to the user, programmers sometimes err on the side of caution.
  • In C++, I've heard arguments against allocating memory in catch blocks (where at least some of the context to make good messages lies). That allocation is hard to manage, and worse, can cause an out of memory exception there - often crashing your app or leaking memory. It's hard to format exceptions nicely without allocating memory, and that practice may have migrated between languages as programmers do.
  • They don't know. I mean, there are scenarios where the code has no idea what went wrong. If the code doesn't know - it can't tell you.
  • I've worked at places where localization concerns prevented putting English only strings into the system - even for exceptions that would only be read by the English speaking support staff.
  • Some places, I've seen exceptions used more like asserts. They're there to provide a clear, loud message during development that something isn't done, or a change has been done in one place, but not another. These are often unique enough that a good message would be duplicated effort or simply confusing.
  • People are lazy, programmers more than most. We spend far less time on the exceptional path than the happy path, and this is a side effect.

Are my expectations out of line? Am I using Exceptions wrong that I even notice this?

Kinda? I mean, exceptions should have nice messages, but they're also exceptions. You should be spending your time designing code to avoid exceptional conditions, or writing code to handle exceptional conditions (ignoring the message), not using them as a sort of interactive feedback mechanism when coding. It's unavoidable to use them for debugging purposes, but in most situations that should be kept to a minimum. That you notice this problem makes me concerned that you're not doing a good enough job at preventing them.

  • I'm aware this has been tagged as C but I should add that your last paragraph does not apply to all languages as some can (rightly or wrongly) rely heavily on exception-based error handling and reporting. – Lilienthal Apr 13 '15 at 17:36
  • 1
    @Lilienthal - such as? No language I am very familiar with does that sort of thing regularly. – Telastyn Apr 13 '15 at 17:48
  • 1
    I think this answer has a lot of good content, but it avoids saying the bottom line, which is "They should." – djechlin Apr 13 '15 at 18:55
  • 3
    Thanks. Your concern is unfounded (I hope :-). But every time I spend an extra minute tracking down what went wrong in that Unit Test or spend extra time analysing code because the logfile is lacking info, I'm a tad annoyed by the avoidable crappiness of some messages :-) – Martin Ba Apr 13 '15 at 19:24
  • @Telastyn SAP's proprietary ABAP has an exception class construct can contain a message, which is basically an object specifically meant to report program state (success, failure, warning) to the user along with a dynamic (multi-lingual) message. I'll admit I don't know how widespread this kind of thing is, or if it's even encouraged in the languages were it's possible but there's at least one where it's (regrettably) common practice. – Lilienthal Apr 13 '15 at 20:54

I don't have an excess of C# experience, or C++ specifically, but I can tell you this - developer-written exceptions 9 out of 10 times are more useful than any generic exception you will ever find, period.

Ideally yes, a generic exception will point you to exactly why the error occurred and you'll be able to fix it with ease - but realistically, in large applications with multiple classes that can throw a wide variety of different kinds of exceptions, or the same kind of exceptions, it is always more valuable to write your own output for error return than it is to rely on the default message.

This is how it should be, because as many people have pointed out, some applications don't want to throw an error message that they don't want the user to see, for security reasons or to avoid confusing them.

Instead, you should anticipate in your design what types of errors might be thrown in your application (and there will always be errors) and write error-catching messages that help you identify the issue.

This won't always help you - because you can't always anticipate what error message will be useful - but it is the first step to understanding your own application better in the long-run.

The question is specifically asking why do so many exceptions thrown by "system components" (aka standard library classes) not contain useful details.

Unfortunately, most developers do not write the core components in standard libraries, nor are detailed design documents or other design rationale necessarily made public. In other words, we may never know for sure.

However, there are two key points to keep in mind as to why detailed exception information might not be desirable or important:

  1. An exception may be used by calling code in any way: a standard library cannot place constraints on how the exception is used. Specifically, it may be displayed to the user. Consider an array index out of bounds: this may give useful information to an attacker. The language designer has no idea how an application will use the thrown exception or even what type of application it is (e.g. web app or desktop), so leaving out information may be safer from a security perspective.

  2. Exceptions should not be displayed to the user. Instead, display a friendly error message and log the exception to a location an attacker has no access (if applicable). Once the error is identified, a developer should debug through the code, inspecting stack frames and logic paths. At this point, the developer has more information than an exception could ever hope to have.

  • 3
    1. Based on this criteria it seems relatively arbitrary what information is ("Index out of range", stack trace) and isn't (value of index) shown. 2. Debugging can potentially be a lot faster and easier when relevant dynamic values are known. For example it would often immediately tell you whether the problem is garbage input to the piece of code that failed, or that code failing to correctly deal with good input – Ben Aaronson Apr 13 '15 at 15:58
  • @BenAaronson the identity/class of the exception tells us the type of error. My point is the details might be omitted (i.e. what specific value caused the error) for security. That value might be traceable back to the user input, revealing information to an attacker. – user22815 Apr 13 '15 at 16:00
  • @Snowman I hardly think security is a consideration when a full stack trace is available, and index number is not. Sure I understand an attacker probing for buffer overflows, but many exceptions leave out quite safe data too (eg which Oracle table wasn't found) – gbjbaanb Apr 13 '15 at 16:33
  • @gbjbaanb who says we need to show the full stack trace to the user? – user22815 Apr 13 '15 at 16:37
  • 1
    Thanks for sharing that insight. Personally, I don't agree and think the security argument is a complete fallacy, but it may be a rationale. – Martin Ba Apr 13 '15 at 19:38

First off, let me burst a bubble by saying even if the diag message is loaded with information that brings you to the exact code line and sub command in 4 seconds, chances are the users will never write it down or convey it to the support folks and you will be told "Well it said something about a violation... I don't know it looked complicated!"

I've been writing software and supporting the results of others software for more than 30 years now, and personally, the current quality of an exception message has virtually nothing to do with security, regardless of how the end results happened to fit their model of the universe, an much more to do with the fact that so many in our industry were originally self taught, and they just never included lessons in communications. Maybe if we FORCED all new coders into a maintenance position for a couple of years where they had to deal with figuring out what went wrong, they would understand the importance of at least some form of precision.

Recently in an application being rebuilt, a decision was made that return codes would fall into one of three groups:

  • 0 through 9 would be success through success with additional information.
  • 10 through 99 would be non fatal (recoverable) errors, and
  • 101 through 255 would be fatal errors.

(100 was for some reason left out)

In any particular workflow, our thought was reused or generic code would use generic returns (>199) for fatal errors, leaving us with 100 fatal errors possible for a work flow. With slight differentiating data in the message, errors such as file not found could all use the same code and differentiate with the messages.

When the code came back from the contractors, you would not believe our surprise when virtually EVERY SINGLE FATAL ERROR was return code 101.

All that considered I think the answer to your question is the messages are so meaningless because when originally created, they were to be placeholders that no one got back to. Eventually folks figured out how to fix issues not because of the messages but DISPITE them.

Since that time, the self taught folks simply never had a good example of what an exception should contain. Add to that more users don't read the messages, much less try to pass it on to support (I've seen error messages that were cut and paste by the used that were then redacted before being sent on with the later comment that it seemed like a lot of information and I could not possibly want it all, so they randomly removed a bunch of it.

And lets face it, with way too many (not all but way too many) of the next generation of coders, if it is more work and does not add flash, just not worth it...

Last note: If an error message includes an error/return code, it seems to me that somewhere in the executed modules there should be a line that reads something like "if condition return code-value" and condition should tell you why the return code occurred. This seems like a simple logical approach, but for the life of me, just TRY to get Microsoft to tell you what happened when a windows upgrade failed on CODE 80241013 or some other very unique identifier. Kinda sad, isn't it?

  • 8
    "...you would not believe our surprise when virtually EVERY SINGLE FATAL ERROR was return code 101." You're right. I would not belive you were surprised when the contractor followed your instructions. – Odalrick Apr 15 '15 at 11:55
  • 3
    chances are the users will never write it down... and you will be told "Well it said something about a violation..." This is why you use an exception logging tool to automatically generate the error report containing the stack trace and possibly even send it to your server. I had one user one time who was not very technical. Every time she would submit a message from the error logger, it would go something like "I'm not sure what I did wrong, but..." no matter how many times I explained that this error meant the bug was on my side. But, I always got the error reports from her! – Mason Wheeler Apr 28 '15 at 21:21

While I do agree that exceptions should contain as much information as possible, or at least be less generic. In the table not found case, the table name would be nice.

But you know more about what you were trying to do at the place in the code where you received the exception. While you often really can't do much to rectify the situation when something goes wrong in a library outside your control, you can add much more useful information on in which situation something has gone wrong.

In the case of table not found, it will not help you much if you are told that the table that cannot be found is called STUDENTS, because you do not have such a table, and that string is nowhere in your code.

But if you catch the exception and rethrow it with the SQL-statement you were trying to execute, you will be better off, as it turns out that you tried to insert a record with the name field being Robert'); DROP TABLE STUDENTS; (There is always an xkcd!)

So to combat the less than informative exceptions: try-catch-rethrow with more information specific to what you were trying to do.

I should probably add, for this to be more of an answer as to the why in the question, that a likely reason why the focus from the makers of the libraries has not been on making the exception messages better, is that they do not know why something has been tried that failed, that logic is in the calling code.

  • e.g. in C++ you should use throw_with_nested a lot. – Miles Rout Apr 14 '15 at 23:01

To give a slightly different answer: The offending code has probably been done to spec:

  • The function receives X and returns Y
  • If X is invalid, throw exception Z

Add the pressure to deliver exactly to spec (for fear of being rejected in review/testing) in minimum time and with minimum fuss, then you have your recipe for an entirely compliant and unhelpful library exception.

Exceptions have a language- and implementation- specific cost.

For example, C++ exceptions are required to destroy all the living data between throwing call frame and catching call frame, and that is expensive. Hence, programmers do no wish to use exceptions a lot.

In Ocaml, exception throwing is nearly as fast as a C setjmp (its cost does not depend upon the number of traversed call frames), so developers can use it a big lot (even for non-exceptional, very common, cases). In contrast, C++ exceptions are heavy enough so you probably won't use them a lot like you would in Ocaml.

A typical example is some recursive search or exploration which can be "stopped" inside a quite deep recursion (e.g. find a leaf in a tree, or a unification function). In some languages it is quicker (so more idiomatic) to propagate that condition to every caller. In other languages, throwing an exception is quicker.

So depending on the language (and the habits of developers using it), an exception could carry a lot of useful details, or on the contrary be used as a quick non-local jump and carry only the very useful data.

  • 6
    "For example, C++ exceptions are required to destroy all the living data between throwing call frame and catching call frame, and that is expensive. Hence, programmers do no wish to use exceptions a lot." Total crap. The main strength of C++ exceptions is that destructors are called deterministically. Nobody would use them if they just jumped. – Miles Rout Apr 14 '15 at 22:57
  • I know that, but it is a fact that C++ exceptions are not like Ocaml, and you don't use them like you do in Ocaml. – Basile Starynkevitch Apr 15 '15 at 4:18
  • 5
    You don't use C++ exceptions for control flow in C++ primarily because doing so makes code unreadable and hard to understand. – Miles Rout Apr 15 '15 at 5:11

What makes you think the index value or the required range or the name of the table is a useful detail, for an exception?

Exceptions aren't an error handling mechanism; they are a recovery mechanism.

The point of exceptions is to bubble up to the level of code that can handle the exception. Wherever that level is, either you have the information needed, or it is not relevant. If there is information you need, but don't have immediate access to, you are not handling the exception at the appropriate level.

The one time I can think of where extra information could be helpful is at the absolute top level of your application where you crash and emit an error dump; but it is not the job of the exception to access, compile and store this information.

I'm not saying that you can just put "throw new Exception" everywhere and call it good, it is possible to write bad exceptions. But including irrelevant information is not nessecary to use them properly.

  • I wouldn't describe the name of the missing database table as irrelevant although I do understand, and sympathise with, the point you are making. I've given you an up vote. – Daniel Hollinrake Apr 20 '15 at 7:24
  • 1
    @DanielHollinrake Yes, the table name is definitely the least irrelevant of the examples. In the code I work with, this kind of problem is depressingly common and looking at how the table name has been mangled gives clues to what is wrong. I've been trying to think of an example why these things are irrelevant to the exception; maybe I can use this... – Odalrick Apr 20 '15 at 11:23
  • I disagree. For handling an exception additional details might not be required because you just want to protect the application from crashing but finally you will need to tell why it didn't work and be able to fix it. If you don't have any clues but the exception type then good look debugging. – t3chb0t Nov 4 '15 at 12:14
  • @t3chb0t That is what the stack trace and class of the exception and memory dump and everything else is for. How would it help you if a customer calls in and says "The computer tells me that that it tried to access index 5 and it wasn't there.". It could only help if you also serialize the list, and the context for the list and anything else that might be useful. You should not serialize the entire state of the application every time you throw an exception. – Odalrick Nov 4 '15 at 15:35
  • @Odalrick for the customer it might not have any meaning but as a developer I value every information I can get ;-) then maybe another example: let's say a SqlExeption occurs and that's everything you know... It is much easier to repair it if you know which connection string or database or table etc didn't work.... and this is even more important if your application uses several databases. A detailed stack trace requires pdb-files to be shipped with the application... it is not always possible. Also memory dumps can become very large and cannot always be transfered. – t3chb0t Nov 4 '15 at 17:08

protected by gnat Apr 14 '15 at 17:30

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.