252

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?

Martin Ba
  • 7,578
  • 7
  • 34
  • 56
  • 67
    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
  • 133
    @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
  • 3
    @MasonWheeler - it's old (~12 years now), but back when I worked at Symantec, there was an interesting stat about attacks - 80% originated from the _inside_ of the network. Your system is always open to the disgruntled IT guy or the mischievous new hire. (not that I necessarily agree with this justification for shoddy exception messages). – Telastyn Apr 13 '15 at 14:31
  • 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
  • @Snowman: Yes, that's exactly the point of my original comment. – Mason Wheeler Apr 13 '15 at 14:46
  • 1
    I suspect the answer to your question is "because that's what debugging is for." Also, some exceptions are caught and rethrown. Look in the `InnerException` property of the exception object for more details. – Robert Harvey Apr 13 '15 at 15:00
  • 15
    Related reading: [How to write a good exception message](http://programmers.stackexchange.com/q/29433/22815) and [What is the proper response to lousy error message?](http://programmers.stackexchange.com/q/88136/22815) –  Apr 13 '15 at 15:10
  • 3
    @RobertHarvey: knowing what the number exactly can be helpful during development, for example, if you know that you're passing save(age=42,favcolor=2) to a function and you get "ArgumentsOutOfRange: 42 is not a valid index for favoriteColor List", you'll immediately know where to look as the bug is likely related to the age variable instead of having to dig into the debugger to find what the value is. It can be especially worse if there are random values involved as you might have to wait until you stumble upon the right random values again. – Lie Ryan Apr 13 '15 at 15:52
  • 4
    @RobertHarvey What?! How is "negative or greater than Size-1" two values? Especially when Size is potentially only known at runtime. Debugging's great if you have a relatively good understanding of the bug or at least repeatable steps to reproduce, but it's wildly optimistic to assume that every bug reported based on a stack trace and Exception type will automatically be: a) Trivial to understand/reproduce or b) Just so happen to occur on a developer's machine while they're debugging – Ben Aaronson Apr 13 '15 at 15:52
  • @RobertHarvey I agree with that point, but since `ArgumentOutOfRange` doesn't expose the argument value as either a message or property, I'm not sure I see the relevance to this example. The question title says "Exceptions", not "Exception messages" – Ben Aaronson Apr 13 '15 at 15:57
  • @BenAaronson: Now it does. (it also says that in the body of the question). – Robert Harvey Apr 13 '15 at 15:58
  • @MasonWheeler In that case **you** the developer should be adding those error messages in, and not relying on the default error messages. – Zibbobz Apr 13 '15 at 17:03
  • 8
    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
  • It's worth noting that in some cases it's not possible to give much useful info - see the (in)famous case of `NullReferenceException` in C#. – anaximander Apr 14 '15 at 08:59
  • @anaximander While it is certainly true that in some cases it's not possible to provide more details in a meaningful manner, that does not preclude the possibility of providing additional details when doing so *is* practical. – user Apr 14 '15 at 09:41
  • 4
    @MichaelKjörling I totally agree; just pointing out that it's not *always* the fault of the developer. Sometimes the reason there's no info is because they can't tell you, regardless of how frustrating it is to not know *what* was null (for example). – anaximander Apr 14 '15 at 09:44
  • 5
    Many programmers with C backgrounds use exceptions like they used error error codes: static and immutable. They forget that exceptions can be built-up at runtime. Hence "File not found" instead of "file %s not found." – Moby Disk Apr 14 '15 at 14:38
  • 1
    @anaximander: It *would* actually have been possible to give more useful information in NREs when the platform was originally designed. The VM could easily have added "An instance of type IFoo was expected." I would have liked to have that information. – Jørgen Fogh Apr 14 '15 at 15:31
  • @MasonWheeler - not all computer _users_ are computer _owners_ - company machines used by one or more employees, for example. – HorusKol Apr 16 '15 at 01:17
  • 2
    @Telastyn's argument is distracting. It is true that the internals of the system should not be exposed to users, but that does not imply that error messages must not contain any useful information. Just don't send the errors to the client in production. e.g. on all PHP installs I've used, the default setting is `display_errors = Off`. – Jackson Apr 19 '15 at 16:47
  • 1
    @JørgenFogh, FYI, Java recently added more helpful NullPointerExceptions with [JEP 358](https://openjdk.java.net/jeps/358) in [Java 14](https://openjdk.java.net/projects/jdk/14/). – siegi Oct 08 '20 at 19:44
  • If the security of your system depends on obscuring details of you system: you have no security. – Ian Boyd Jul 13 '22 at 13:36

11 Answers11

235

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.

Ardent Coder
  • 105
  • 1
  • 1
  • 7
Mike Nakis
  • 32,003
  • 7
  • 76
  • 111
  • 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
  • Yeah, beats me. But luckily, this means that there is room for things to mature in the future. – Mike Nakis Apr 13 '15 at 16:20
  • 9
    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
  • 52
    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
  • 2
    Sure, I almost agree that an exception should contain a code only and that an "error message" is redundant in such cases. However, this just shifts the problem to a stack of error codes which requires even more rigour in writing them, at least with an error message you can type out whatever you like at the time and prevents a plethora of exception objects being defined for every error case. – gbjbaanb Apr 13 '15 at 16:25
  • 1
    @ThomasOwens I amended my answer to address your concern. – Mike Nakis Apr 13 '15 at 16:39
  • 2
    @gbjbaanb well, by human-readable I meant user-readable. But of course yes, any fool knows we programmers are hardly human. – Mike Nakis Apr 13 '15 at 16:40
  • @gbjbaanb I am afraid you misunderstood me: I was definitely **not** talking about error codes. I shall repeat myself: **the message of the exception is the (fully qualified) *class name* of the exception.** – Mike Nakis Apr 13 '15 at 16:41
  • @MikeNakis fundamentally, what's the difference? A code is a value that means something, whether it is an int or a pointer or a compiled runtime object. They're all a single value, no matter how you dress them up differently. You may be thinking of C-style #defines when I say "error code" but that's not necessarily the case. Single value however is. – gbjbaanb Apr 13 '15 at 17:38
  • 67
    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
  • @gbjbaanb the difference is that in the case of class names, for the most part you already have them, you don't have to invest any rigour in coming up with new ones, and they are hierarchical (with inheritance) and extensible: you can write a new module which extends the exceptions of an existing module without having to modify the source code of the existing module. – Mike Nakis Apr 13 '15 at 18:53
  • @MasonWheeler of course, in many scenarios it is okay. But in this discussion (and in other answers) we are addressing the issue of what to do when it is not okay. – Mike Nakis Apr 13 '15 at 18:55
  • 4
    I have a dream now - to program in a world where software is through-and-through designed with this kind of attention to exception handling and logging. If only we could get back all the person-days that have been lost to trying to figure out what an error means and what generated it when it was something stupidly trivial that we'd have easily solved if it was just made clear where the error was coming precisely (with variable values included)... – BrianH Apr 13 '15 at 21:28
  • 1
    It just dawned on me that there is absolutely no reason why someone couldn't give `ArgumentOutOfBoundsException` this functionality and submit the pull request... – RubberDuck Apr 14 '15 at 00:13
  • 3
    This is a great answer and philosophy, but I'm a little skeptical about storing *binary* serializations in log files. I might favor something more portable and slightly more human readable like JSON, so that some kind of binary reader isn't *required* to view the details and giving programmers more options for readers. (E.g., maybe the best reader is in .NET but I'm writing Java.) – jpmc26 Apr 14 '15 at 04:15
  • 17
    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 04:52
  • @MikeNakis but you do not "already have them" - somebody somewhere made them up. They could have made up #define return codes just as easily TBH. Think it through - you're just dressing up one system with something better looking. Now, putting codes or text in the exception objects, that makes more sense and starts to build error information that helps. Eg IndexOutOfBounds passing the index that was used so you can see if it was uninitialised value, -1 or 7 in a 6-element collection. – gbjbaanb Apr 14 '15 at 07:21
  • 2
    @jpmc26 the stream does not *have to* be binary, so I amended my answer to reflect that. The point I am trying to make is that if you don't want users to see it, then you have to encrypt it, meaning that you will need a tool to view it, in which case the pre-encryption stream might as well be binary, which would in turn be sufficient to prevent most users from seeing it, thus making encryption unnecessary. – Mike Nakis Apr 14 '15 at 10:29
  • @MichaelHampton the log files do not *have to* be binary; they may be binary if you want privacy and / or performance. I amended my answer to reflect that. It is just that with a binary log file serialization of exceptions comes practically for free. Also, I would not judge an entire methodology based on one or two possibly unfortunate implementations. – Mike Nakis Apr 14 '15 at 10:31
  • Servers shouldn't be sending out details from a security perspective all my server error messages just asks the user to try again and gives out a support code so I can look at the exceptions which do contain everything I need to debug. They added Data for a reason I even serialize full pocos sometimes into the data section for debugging. I also do use Application defined exceptions for very specific things like the answer says I never implement a message. I think it's time to issue pull requests on the open sources parts of the framework ;) – Zonder Apr 14 '15 at 10:35
  • 1
    I don't agree that an exception message is its own name. For example. We do not want to create an exceptions for every single possible error. Furthermore some exceptions like System.Runtime.Remoting.ServerException are not very informative at all. The message can save lots of hours. And programmer time is money. – Borjab Apr 14 '15 at 13:16
  • 4
    @user119591 If your `ServerException` does not have a `Cause` which is some more specific exception, explaining precisely what went wrong, then your `ServerException` is as good as the proverbial "An unknown error occurred" message. Good luck with that. – Mike Nakis Apr 14 '15 at 15:26
  • 2
    @user119591: And in some cases the Cause is better that nothing but not too helpfull. For example: Caused by NullPointerException in org.apache.FooBar. Now you need to A) download Apache sources, B) understand what it is happening in this exception. Compare it with: Unable to start server. Port 80 is already in use. – Borjab Apr 14 '15 at 16:12
  • 1
    @gbjbaanb No, Mike is correct. An exception class is fundamentally different than an error code. Exceptions have descriptive, compiler enforced names that communicate the actual error via the name. The name is usually enough to make sense of what the exception means, and a little documentation on the exception class is sufficient when it's not. It's sufficiently easy/reliable to write the correct exception name, as opposed to choosing the correct error code. And the compiler or runtime ensures the existence of the exception you use. Error codes have none of these benefits. – jpmc26 Apr 14 '15 at 16:44
  • 1
    @jpmc26 so apply what you said to a const int. It can have just as good a descriptive name, can be commented equally well, its easy to type out the name (even via intellisense) and the compile will ensure the existence of this code. You're mistaking the type of thing with the information it conveys. Hence an exception class that is simply a language entity is no different from a code - they both convey 1 piece of information that is equally useful in diagnosing the problem. Thus I think adding more info is better, don't get caught up in exception v error ideology, think of the data. – gbjbaanb Apr 14 '15 at 16:51
  • 1
    This answers seems highly geared towards maintaining a cooperate software environment. In other environments their are other important things to consider. For example while programming it is pretty important for the IDE/commandline/server/browser to print out human readable and informative errors as you compile and test the code.not just create an encrypted binary logfile. – Jonathon Apr 14 '15 at 18:53
  • The log file does not *have to* be binary. It can, possibly, be binary. The point I am making is that it needs to be thought of as a stream, into which exceptions can be serialized, which in turn serves to support the argument that exceptions do not have to create human-readable messages for storing in log files. So, if you have no security issues, the log file could be plain text xml, containing something like `...` – Mike Nakis Apr 14 '15 at 20:08
  • 1
    "the concept of exceptions has not matured yet enough within the software engineering discipline" - say what? Really?! – MrWhite Apr 14 '15 at 22:16
  • 4
    @w3d: I think the fact that so many exceptions contain English "explanations" is proof that that statement is correct. – Mooing Duck Apr 14 '15 at 22:18
  • 3
    I vehemently disagree with the idea that logs should be obfuscated, binary, or otherwise hidden from the user. In the oracle table not found exception mentioned, an admin may be able to understand that a table is missing, check his database backups, and find that yes, that table is missing... let's restore the good backup and be on our way and there is no need to send some binary log file to the developers and hope they get back to you. Another example are Windows NT crash exceptions, aka BSODs. An admin might not be able to fix the bug but he can see which driver is broken and disable it. – psusi Apr 14 '15 at 23:01
  • 1
    @gbjbaanb Think about the data? Sure. First, the compiler/runtime can't enforce that you even use a named constant for your error code, since the type is just a string or int. Anyone can throw a magic number/string into any location where the error occurs, so a descriptive name might not even exist. Second, being a simple string or int type, it can't have additional contextual details attached to it to aid in diagnosing. This a major point of this answer: exceptions have the ability to carry *more* data and we should be using it. At minimum, an exception is a full DTO, not just a code. – jpmc26 Apr 15 '15 at 02:34
  • Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackexchange.com/rooms/22856/discussion-on-answer-by-mike-nakis-why-do-many-exception-messages-not-contain-us). –  Apr 15 '15 at 02:38
  • 4
    "*Exceptions do not contain useful details because the concept of exceptions has not matured yet enough...*" While I think that this is correct, it *really* just begs the question: ***why not?*** I've been a programmer for over 35 years, and it is something that has puzzled me every one of those years. Despite having been around even longer than me (45+ years) and being a central part of good programming, exceptions and exception-handling have been consistently treated like the secret monstrous child the family keeps locked in the basement and never talks about. Puzzling ... – RBarryYoung Apr 17 '15 at 11:31
  • 1
    @MikeNakis good point, do you have any references for people willing to study this further? – Eric.Void Nov 24 '15 at 17:16
  • 1
    @Eric.Void unfortunately no, I do not. All this comes from my personal experience. – Mike Nakis Nov 24 '15 at 18:01
  • @MikeNakis "the pre-encryption stream might as well be binary, which would in turn be sufficient to prevent most users from seeing it, thus making encryption unnecessary" Using a binary format to save space makes sense. Using it to replace encryption makes *no* sense. If the user can access it, they will be able to decode it, at least the users you're worried about. And if they can't, it doesn't matter. – Solomon Ucko Sep 22 '21 at 15:59
48

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.

Telastyn
  • 108,850
  • 29
  • 239
  • 365
  • 1
    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
  • 4
    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
  • 1
    A string buffer should be allocated on the stack rather than the heap, since it is only needed until it is written to the error log, and stack allocation works just fine in a catch block. – psusi Apr 14 '15 at 23:22
14

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.

Zibbobz
  • 1,522
  • 3
  • 13
  • 20
7

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. –  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? –  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
  • @MartinBa I cannot find a link to this but at a previous employer we had to scrub SQLException strings coming back from SQL Server's JDBC driver. If the login info was incorrect, it would have the plaintext username and password embedded in the exception text. Despite the log files not being user-accessible, it was still a breach of financial regulations and we had to scrub the data while keeping the exception. It had valuable information for developers to figure out why a connection failed. –  Apr 13 '15 at 19:56
  • 2
    Yet, [Jon Skeet wrote](https://twitter.com/jonskeet/status/636846808325603328): "System.InvalidCastException would be so much more useful if the error message included the requested target type and actual type." – Peter Mortensen Oct 18 '15 at 14:11
4

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?

Randy
  • 65
  • 2
  • 9
    "...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
  • 5
    `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
3

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.

Basile Starynkevitch
  • 32,434
  • 6
  • 84
  • 125
  • 9
    "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 04:18
  • 7
    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 05:11
  • @MilesRout "destructors are called deterministically" is exactly what Basile was describing there. – Caleth Sep 22 '21 at 08:40
3

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.

Bent
  • 2,566
  • 1
  • 14
  • 18
3

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.

Stu Pegg
  • 568
  • 2
  • 13
2

TL;DR: No code should ever interrogate an Exception's Message property.

Why do many exception messages not contain useful details?

Arguably, because none of them should!

Exception Objects should carry as much information as is useful for an Exception Handler to do its job, i.e. to "handle" the Exception and make it "go away".

The class of an Exception and, in some technologies, its properties can be used to selectively catch an Exception for handling. Why is there no such mechanism that can be used with the Exception's Message? Because the designers of Structured Exception Handling architectures realised this, simple truth ...

Exception Messages are largely redundant Documentation, intended for people, not programs.

Exception Messages are there largely for the Application's "back-stop" Exception Handler, way up at the very top of the Call Stack, that catches the Exception and logs it away for diagnostic purposes just before the Application crashes and burns.

Having a big, headline Error Message in the Log File makes it easy to spot.

Exception Messages also have a nasty habit of being edited, re-worded, shuffled-about-a-bit or translated by Developers who think that the existing wording is clunky or meaningless or overly-wordy or technically inaccurate or 101 other reasons and, when they do so, any code that expects to find particular "bits" of "useful" stuff embedded in the Message suddenly stop working.

Phill W.
  • 11,891
  • 4
  • 21
  • 36
  • Then, instead of writing a long winded comment on why I think you're totally off the mark, I think I'll just share my exisiting thoughts on this: https://stackoverflow.com/a/27825133/321013 – Martin Ba Oct 09 '20 at 18:37
  • I just noticed *"TL;DR: No code should ever interrogate an Exception's Message property."* that I totally agree with your TL;DR. But it totally misses the point, because no code will inspect the Message except for dumping it out to logs. – Martin Ba Oct 12 '20 at 20:04
1

Most programs have two requirements:

  1. Behave usefully when practical.

  2. When unable to behave usefully, behave in tolerably useless fashion.

In many cases, exceptions are used as a means of meeting the second requirement as cheaply as possible. Having a program report why it is unable to perform its primary task may be somewhat more useful than having it simply refuse to perform the task without stating a reason, but such benefit might not be worth the cost of trying to provide more detailed information.

Note that this philosophy is rather different from that of "modern" compilers based on gcc or LLVM, which take the attitude that if a program can't perform usefully, all possible behaviors should be regarded as equally satisfactory. Exception handling is designed around the presumption that the marginal value in ensuring that attempts to process erroneous data will be acceptably harmless is larger than the marginal value of making it easy to respond to such data somewhat usefully.

supercat
  • 8,335
  • 22
  • 28
  • Ah, your crusade against leaving anything undefined raises its head again. Honestly, I cannot see how the level of (hopefully useful) detail conveyed by exceptions (aka the OPs question) impinges on it. – Deduplicator Sep 21 '21 at 23:11
  • @Deduplicator: My point is that the design of exceptions is focused largely on minimizing the amount of effort programmers must make to satisfy the second objective above. Designing an exception-handling mechanism to supply more information about what exactly went wrong would significantly impede efficiency even in cases where everything goes right. Keeping execution on the rails isn't free, but for many applications the benefits can vastly outweigh the cost, especially if the costs are minimized by focusing on what's actually important. – supercat Sep 21 '21 at 23:27
  • @Deduplicator: While some places in the framework could cheaply add more detail to exception messages, a call to a parameterless function which throws an exception is cheaper than a call which has to set up arguments about the array, the index code was trying to use, etc. Since such code will be needed for almost every array indexing operation in the program, the cost of the code to handle all that parameter setup would quickly add up. – supercat Sep 21 '21 at 23:33
  • So, you are saying UB is "being cheap", throwing exceptions without all details is "being cheap", and thus the former is relevant here? That is a bit far-fetched, there are many more things more commonly claimed "being cheap" which are no less related, but I contend still irrelevant. – Deduplicator Sep 21 '21 at 23:43
  • @Deduplicator: My point is that I think MS sought to do enough to meet a certain functionality target, and I described what I perceived as that target. Even though the cost of going beyond might not have been huge, the marginal value wasn't as great as the value of reaching the target. – supercat Sep 22 '21 at 14:40
0

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.

Odalrick
  • 350
  • 1
  • 5
  • 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 07: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
  • 1
    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 04 '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 04 '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 04 '15 at 17:08
  • @t3chb0t Yes, there is certainly information you can log that would help. My point is that it isn't in the exception you should log that information, it is in the code that handles that exception. If your code drops an unhandled exception on the lap of the customer, that is already at least three levels of fail; especially if it is such a low level exception as SqlConnectionFailed. Adding random bits of transient data to the message of the exception doesn't help. – Odalrick Nov 05 '15 at 08:16