29

It continue to astounds me that, in this day and age, products that have years of use under their belt, built by teams of professionals, still to this day - fail to provide helpful error messages to the user. In some cases, the addition of just a little piece of extra information could save a user hours of trouble.

A program that generates an error, generated it for a reason. It has everything at its disposal to inform the user as much as it can, why something failed. And yet it seems that providing information to aid the user is a low-priority. I think this is a huge failing.

One example is from SQL Server. When you try and restore a database that is in use, it quite rightly won't let you. SQL Server knows what processes and applications are accessing it. Why can't it include information about the process(es) that are using the database? I know not everyone passes an Applicatio_Name attribute on their connection string, but even a hint about the machine in question could be helpful.

Another candidate, also SQL Server (and mySQL) is the lovely string or binary data would be truncated error message and equivalents. A lot of the time, a simple perusal of the SQL statement that was generated and the table shows which column is the culprit. This isn't always the case, and if the database engine picked up on the error, why can't it save us that time and just tells us which damned column it was? On this example, you could argue that there may be a performance hit to checking it and that this would impede the writer. Fine, I'll buy that. How about, once the database engine knows there is an error, it does a quick comparison after-the-fact, between values that were going to be stored, versus the column lengths. Then display that to the user.

ASP.NET's horrid Table Adapters are also guilty. Queries can be executed and one can be given an error message saying that a constraint somewhere is being violated. Thanks for that. Time to compare my data model against the database, because the developers are too lazy to provide even a row number, or example data. (For the record, I'd never use this data-access method by choice, it's just a project I have inherited!).

Whenever I throw an exception from my C# or C++ code, I provide everything I have at hand to the user. The decision has been made to throw it, so the more information I can give, the better. Why did my function throw an exception? What was passed in, and what was expected? It takes me just a little longer to put something meaningful in the body of an exception message. Hell, it does nothing but help me whilst I develop, because I know my code throws things that are meaningful.

One could argue that complicated exception messages should not be displayed to the user. Whilst I disagree with that, it is an argument that can easily be appeased by having a different level of verbosity depending on your build. Even then, the users of ASP.NET and SQL Server are not your typical users, and would prefer something full of verbosity and yummy information because they can track down their problems faster.

Why to developers think it is okay, in this day and age, to provide the bare minimum amount of information when an error occurs?

It's 2011 guys, come on.

4
  • 11
    Wow, that's quite a rant. Jan 17, 2011 at 14:06
  • 3
    @George, can you tell I've just spent a long time tracking something down that really could have been solved faster given a proper error? :)
    – Moo-Juice
    Jan 17, 2011 at 14:08
  • 4
    I suggest deep breaths, maybe some yoga & meditation. :) (That said, I know exactly how you feel.) Jan 17, 2011 at 14:11
  • 2
    +1 - "string or binary data would be truncated" always drives me crazy!
    – k25
    Jan 17, 2011 at 17:46

12 Answers 12

22

While there are plenty of examples of bad error messages that simply should not be, you must keep in the mind that it isn't always possible to provide the information you'd like to see.

There is also the concern over exposing too much information, which may lead developers to error on the side of caution. (I promise you that pun was not intended, but I'm not removing it now that I've noticed it.)

Sometimes, there's also the fact that a complex error message is useless to the end-user. Siding with information overload is not necessarily a good approach for error messages. (That may be best saved for logging.)

9
  • +1 I didn't even think about the information overload aspect.
    – Ryan Hayes
    Jan 17, 2011 at 14:12
  • I explained in my post that I can understand why some feel that verbosity to an end-user might be useless to them. But are you saying that the end-users of an API (a.g ASP.NET's adaptors), or a database engine (SQL-Server) do not want verbose errors? Something that would save us potentially hours of lost time? I liked the pun, by the way :)
    – Moo-Juice
    Jan 17, 2011 at 14:15
  • 1
    @George, also with regard to information overload and it's usefulness to the end user, again I can see a case for not throwing a full-on stack-trace to the user of a word-processor, lest they have a brown-trouser moment and think they've deleted the internet. However, you've provided an excellent alternative with complex information in the log file. All that message needs to do now is add For further information, see log20111701.txt. This would be a step in the right direction.
    – Moo-Juice
    Jan 17, 2011 at 14:22
  • 2
    @moo Ultimately, what I'm saying is that it's easy to criticize. (I know, I do it often.) However, I try to keep in mind that isn't necessarily easy to tell how much information you should include in an error message. There's plenty of times when I've had to back and output more detailed information than I originally anticipated while debugging. Also, there are plenty of times when an error message wasn't as useful as I had anticipated when creating it. Jan 17, 2011 at 15:32
  • 1
    @moo The crux of the problem is that it isn't always obvious how much information is useful. The examples you provide seem rather obvious. However, it isn't easy to extend that to the general case. Jan 17, 2011 at 16:00
21

Developers are not the right people to write error messages.

They see the application from the wrong angle. They are extremely aware of what went wrong inside the code, but are often not approaching the software from the point of view of trying to accomplish something. As a result, what's important information for the developer is not necessarily important information for the user.

1
  • +1 For a lot of the Framework/API kinds of errors, part of the issue is the developer of the library can't know the context. That said, OP seems mostly concerned with the "something is wrong but I'm not going to tell you where even though I know" kinds of error messages. I guess it's security, right?
    – MIA
    Jan 17, 2011 at 16:52
8

The charitable view:

  • The developer worked closely with the code and struggled to comprehend someone who didn't have their understanding working with it. As a result they think the error messages are fine, they just don't have a good frame of reference by which to judge them.

  • Intelligent error messages are actually hard to do. Not only writing them but you have to work out everything that might go wrong, assess the likelihood and provide useful information (which almost certainly varies based on the context) back to the person reading the message to allow them to fix it.

  • For most applications it's hard to make a good case for the time to do this sort of thing as well as the next developer would really like because errors don't occur that often. Besides, if you had that extra time shouldn't you spend it stopping the errors rather than reporting on them?

The uncharitable view:

  • Error messages and error handling are dull, there are far more interesting things to be working on and my boss is on my back about the next thing. I understand this code, I'll be fine, the next guy will work it out in the end and I'll be out of here by then so it's not my problem.

The reality is probably somewhere in the middle, though my experience actually tells me it's far more the former than the later - basically it's actually quite hard and takes a fair amount of effort to deal with something which probably won't happen.

3
  • I understand where you're coming from in many end-user cases. However, the cases I outlined in my original post can happen frequently whilst writing code against databases. With regards to end-user applications such as a word-processor or a computer game, errors generally shouldn't be happening unless something bad is going on, and even then the error might mean nothing to the end-user (Process Handle Raped By Spawned Injector, Quitting SYstem..... user: "wtf did I do?`). But in the case of SQL Server/ASP.NET, I think more effort could have been made :)
    – Moo-Juice
    Jan 17, 2011 at 15:24
  • @Moo-Juice - I think that comes down to the whole "error messages are hard" thing. Under the hood what actually gets thrown at the database once the optimiser has done it's thing has only a passing resemblance to what you threw at it. Identifying the error is one thing, tracing back what happened to what you passed it is another entirely and absolutely not trivial. Jan 17, 2011 at 15:30
  • some cases may not be trivial. I a simple bit of code somewhere that catches the string/binary data error which pulls all column information from said table, examines the values past and shows which columns would have been in violation. This was trivial. Maybe I am bitching too much because my case-examples are trivial, but I totally understand that this is not always the case. How we stop spawned injectors from raping processes may well be difficult :)
    – Moo-Juice
    Jan 17, 2011 at 15:37
6

Unfortunately, more helpful error messages cost developer time, which equals company money. Products are expensive enough to build as it is. Yes, it would be awesome to have more helpful error messages, and I agree that there should be more useful ones included. However, it's just a fact of life that when you're under a deadline, and money is on the line, you've got to cut something. "Prettier error messages" as managers may see it, will likely be the first thing to go.

4
  • Ah, yes, good point. That ever present concern of cost. Jan 17, 2011 at 14:12
  • I can concede a cost perspective (and damn it, that doesn't mean I have to like it). I can't talk from the standpoint of the developers of SQL Server or ASP.NET, but I do know that it doesn't take that much extra effort to provide a column name. I admit that, for my simple example, it might be solved in an hour. Then there's the other 1000 errors that might be generated. But they could at least start with the common ones :)
    – Moo-Juice
    Jan 17, 2011 at 14:18
  • of course I don't know the internals of SQL server -- but generally speaking, more often than not you don't have those informations at hand at the point the error situation is detected. A formulation like "string or binary data" quite clearly shows you that at the error site, it isn't even clear if the truncated value was a string or a number...
    – Ichthyo
    Jan 17, 2011 at 18:17
  • At some level, this may be valid, but the same problem even crops up in simple perl scripts where simply adding $! to the error message would be immensely helpful. It is cheaper (in terms of developer's time) to write 'die "$path: $!"' than it is to write the utterly useless 'die "Couldn't open $path"' Jun 29, 2011 at 15:46
6

I agree that error messages should be as specific as possible.

One reason for generic error messages is probably the use of error codes. When using exceptions you are free to pass all you need in the error message. Using return codes there is no room to encode a columnname. Perhaps the error is handled by a generic function which doesn't know the context and simply translates the error code to a string.

2
  • it is even worse: while you can trigger errors at very specific points, in order to handle errors you're forced to subsume several possibilities into a class of situations, and handle them with one single recovery. This act of generalisation frequently forces you to discard yet more of the scarce additional context info.
    – Ichthyo
    Jan 18, 2011 at 0:42
  • btw... this mechanism leads to a whole class of funny error messages -- along the lines of "Serious fault -567 in Module dwarf678: No error detected"
    – Ichthyo
    Jan 18, 2011 at 0:46
4
  • Sometimes too much information can be a security risk; you don't know who's reading the error message
  • Sometimes the operation that threw the exception is so complex that it is impossible to get a meaningful message without negative affects to the speed/complexity of the code
6
  • I answered your first point allowing for a change in verbosity to the exceptions thrown in your code. Your second point is moot given that at this point, an error has occurred and speed is no longer a deciding factor (imho). And if producing a verbose error message requires a performance impact PRIOR to throwing the exception then I agree. Move that code to AFTER the exception has been thrown. I don't see either of these points as a valid argument against proper error messages :)
    – Moo-Juice
    Jan 17, 2011 at 14:13
  • True, I suppose that you can search for the information once something's happened rather than keep track of what you might need. Although, if you're in nested loops capturing the indexes/indices might be problematic.
    – StuperUser
    Jan 17, 2011 at 14:17
  • -1 for the first point which I don't agree with, +1 for the second point. Jan 17, 2011 at 15:20
  • 1
    @jon Contrast a generic error message for login errors versus more specific error messages that actually tell you what went wrong. e.g. "We couldn't find that username/password combination" vs "You entered an incorrect password."/"That username does not exist." I seem to recall a vulnerability in ASP.NET where the error message was actually useful in cracking encryption keys. Jan 17, 2011 at 15:52
  • @George - I agree with that example but I don't think it's widespread. Once you've been granted access to an application a certain level of risk disappears as you can assume the person is (a) authorised and (b) could get most of what the needed from the actual application. Jan 17, 2011 at 15:55
3

As a general notice, you should consider that any error or exceptional situation is -- exactly that: exceptional. It cross-cuts the planned and designed procedure. It is incompatible to the way things where planned to work. If this wasn't the case, then there wouldn't be any need to bail out with an error abort.

We programmers are trained to care for self-protection of this planned procedure. Thus, we routinely include some sanity checks to verify our assumptions. When these sanity checks fail, we just know that the plan somehow failed...

Your demand -- it may well look like common sense from the user's perspective -- is impossible to fulfil, if you consider the reality of how such a system works. You ask for an orderly statement with well organised and suitable information added. Moreover, you even ask for this presentation to happen in a way which fits into the general application/handling design. Obviously this information exists somewhere in the system. Obviously it even exists there in an orderly and well organised fashion (lets hope so). BUT at the point the error happens, no one ever planned to make this information available. An error always is a partial loss of control. This loss of control can happen on various levels. It could be the system behaving at runtime differently than planned. But it also could be that the actual implementation turned out much more difficult and different in the details then planned, and there was no budged provision to handle this situation satisfactory. This too is a partial loss of control.

To relate this to the concrete example you gave: If, at the point of the error, the name and type of the table column would be known, and in addition the length of the required space, then there wouldn't be any reason for raising an error, wouldn't it? We could just fix the situation and proceed as planned. The very fact that we're forced to raise an error shows us that matters went astray. The very fact that these informations aren't at hand is the exception.

What I'm writing here may seem as self evident and mere common sense. But in reality it is extremely hard to grasp. We constantly try to understand it by applying moral categories -- like there must be a culprit, there must be a bad lazy person which doesn't care for the poor user, there must be a greedy businessmen which did a way to cheap calculation. All of this is completely besides the point

The possibility of loss of control stems from the very fact that we're doing things in a planned and orderly fashion.

2
  • I have to disagree. It knows something is wrong (it can't perform the operation). To know that something is wrong indicates a knowledge of why it is wrong. This string is to big for that column (or a column in that table). It could tell me, without much work. It's a goddamn enterprise database engine. It knows. But it does not relay that information. Given that the programmer can write a query to run after the fact to find out shows the database engine could do the same. These are not secret undocumented facets. Just a crappy error message :)
    – Moo-Juice
    Jan 17, 2011 at 22:43
  • heh... you should base your argument on logic, not on whishful thinking. Since when does a computer know anything? This isn't Hollywood cinema. A program is a rigid, pre-arranged setup, and when your assumptions are broken, you've lost control. Is this really so difficult to grasp? A computer doesnt understand the program, and so he can't understand when its going wrong. Almost ever, when some consistency check triggers, the execution has already proceeded by thousands of statements and no one knows what data got already corrupted. All you can do is limit the damage
    – Ichthyo
    Jan 18, 2011 at 0:27
2

I work as a support engineer for a software firm and often we see error messages that are new to us. Frequently when I refer these back to our development team, they have to search for the message in the source of the application.

It seems to me that even if it wasn't presented to users, it would safe a lot of time for us if the dev team would add a note to an error message index doc or database whenever they added a new one it would make it far quicker for us to find the cause of customer problems and save them time as well...

4
  • 1
    sorry, that's quite impractical. Who would be responsible for managing that index doc, for keeping it accurate. As any written documentation separate of the code, it would be outdated and start getting a source for new errors the very moment it is written.
    – Ichthyo
    Jan 17, 2011 at 18:21
  • On the contrary, that's the kind of thing a script could extract from the source code, if each error had a unique number, and the description of each was also in the code either in the form of a (specially formatted) comment or as a string. So the doc would be automatically generated with each build. The extracted message could then be quite a bit more detailed than anything you'd want the end user to see. Not a bad idea! Jan 17, 2011 at 22:11
  • you don't need a script for that -- many runtime systems can log the line number or some similar info. Unfortunately this doesn't help with the original problem, becaus this way we just know where an exception was detected but we don't know what went wrong. Finding out the latter is called debugging -- in practice this is an more or less tedious and work intensive task done by humans.
    – Ichthyo
    Jan 18, 2011 at 0:33
  • I'm with @Jeanne - simple enough to incorporate in the code or to have a central index in the code with the error code and their interpretation. Once know where an exception was detected that may be enough to tell you that there is a problem with the environment somewhere rather than something in the code that needs chasing down.
    – glenatron
    Jan 18, 2011 at 9:54
2

The problem you're seeing there is actually one of the side-effects of proper encapsulation and information hiding.

Modern systems are extremely complicated. There is little chance that the average developer is able to hold, in his head, a mental model of the entire system from the UI to the raw binary whilst he is coding any particular task.

So, while a developer is sitting down and coding, say, the bit that restores a database file, his mental model is filled entirely with the bits surrounding the act of restoring a database file. He needs to (and I'm guessing, I haven't written this code) read a file, check properties, read versions, backup existing data, choose a merge/overwrite strategy, etc. Quite likely, if there is even a passing consideration to the UI, its in the error string that he writes in an exception handler. Something like:

catch (IOException error)
{
//File is in use
throw new GenericExceptionParsedByTheUIThread("File is in use.");
}

In this example, the helpful information you're asking about in terms of processes that might be using the file, or even other threads in the DB, are completely out of scope (programatically). There may be hundreds of classes that deal with DB files; importing to those classes information about every other process using the files, or functionality to access the file system and look at the other processes running (assuming those processes are even on THIS machine) would result in what is known as a leaky abstraction; there is a direct cost in productivity.

So that's how these kinds of errors can persist in modern days. Obviously, they all COULD be fixed; but in many cases, there's a lot more overhead involved than one might think (in this case for example, you may have to have this function traverse the enumeration of network connections and shares to see if a remote machine is using this database file for some reason) and the cost is far from trivial.

8
  • @GWLlosa, this is a great answer and one I had not considered. That said (and I can't provide a full code example here), when I get that IOException, before I throw my GenericException, I could 1) Ask the Processes Subsystem for a list of processes. 2) Ask each process what database they are using. 3) Match the process with the database assigned to the one I am trying to overwrite, 4) throw a DatabaseInUse(dbName, processName, applicationName exception. :)
    – Moo-Juice
    Jan 17, 2011 at 15:51
  • 1
    Certainly possible; but the code to match the DB to the process (especially over the network) may be complicated/slow/error prone itself, which could result in some additonal frustration ("I'm just trying to restore the local (*#%^!% file!!!! WHY DO I CARE THAT THE NETWORK SHARES ARE NOT ACCESSIBLE!??!?!")
    – GWLlosa
    Jan 17, 2011 at 15:55
  • 1
    @Moo-Juice: what you propose sounds quite naive. In a massive multithreaded environment like a database you can't just reach out to some global service to get a list of "all xyz". Even to talk to some other service in another thread, you need a lock, which could lead to deadlock of the whole system at worse, it could corrupt other data or at least it could cause additional errors, which you need to handle then as well....
    – Ichthyo
    Jan 17, 2011 at 18:28
  • 1
    That example is indeed very instructive: Typically in such a catch handler, you can't even tell for sure which part in the try block failed (usually there are multiple parts which could cause an IOException). Besides that, it is very likely that at that location you can't tell the name of the file, lest you can tell which logical table corresponds to this file.
    – Ichthyo
    Jan 17, 2011 at 18:31
  • @Ichthyo, no offence but I do not think it is naive at all. I'm not asking the database engine to lock the system up to tell me what process still has a handle to a database. I'm not asking it to bring the entire enterprise to a halt. If it needs to to give me a simple answer, that that shows a fundamental design flaw of the database server in the first place. Remember, it is supposed to be designed to give pertinent information back in the fastest possible way. To ask it the question "who?" really shouldn't be as naive as you state :)
    – Moo-Juice
    Jan 17, 2011 at 22:34
2

My favourite was (back in the late 70's) the Univac Fortran IV compiler, when reading non-digits, faithfully announced

The interpretation of meaningless data was attempted

2
  • +1, absolutely fantastic! It's the kind of error that makes you just want to give up and go and raise chickens in Fiji.
    – Moo-Juice
    Jan 17, 2011 at 15:53
  • indeed, this error message is 100% accurate -- if you want a more friendly message with more conetxt, you need to build in some guesswork and heuristics; this way you add the possibility of misleading error messages..
    – Ichthyo
    Jan 18, 2011 at 0:39
0

I believe the majority of error messages are actually programmer (self) oriented glorified debugging code/printf statements.

Writing user-oriented error messages means knowing who your user is, and anticipating what they will want to know. While in the middle of writing code, a developer is more apt to write an error message useful to themselves, for either debugging the code they are writing at the moment, or useful for the known or predominate Use Case(s).

Switching from writing code to designing a textual portion of the user interface (or user experience) is a context switch. In large applications, such as multilingual applications that could mean it gets handed off to a different person or team (UI, translation) rather than entirely handled by the developer, so unless the developer carefully explains the context of the message, important details can be easily lost.

Of course, checking and verifying error handling is often considered a low priority, as long as errors & exceptions are handled (i.e. caught), not much emphasis is given to it. It's a mentally unrewarding place of the codebase for developers or QA to evaluate, as error conditions often have a negative connotation (i.e. mistake or failure) associated with them.

0

I think the reason is that error reporting/handling are always done as an after thought. Even when they are not entirely after thought, they're mostly second class citizens in the overall design.

Modern software usually consists of multiple layer. When your error reporting logic is laid down in a rush without too much thought, it's often difficult to gather all the information required to present useful error messages.

For example, the error is caught in the back-end, but it needs some information from higher layers to compose a comprehensive error message. Most good error messages need information from almost all layers (to give us a comprehensive view of what happened in the system). The ideal error message would look like "OK, we first received a string, then it passed through the parser which gave something funny, you might want to look there. Anyway, the thing was passed further down..."

Doing it would often require unnecessary coupling if the error reporting mechanism was not first class citizen during design phase. I guess most people just find that too much work to do for something that doesn't look impressive (who likes to say "See? My program crashed, and the error message is useful!").

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