Michael Eriksson
A Swede in Germany
Home » Software development | About me Impressum Contact Sitemap

Error messages

Introduction

The following is a discussion of some problems with error messages. Note that I use “error message” in a very wide sense, largely because “Messages” would have made an overly ambiguous title for this page.

GUIs

Too many error messages provided by modern applications are useless or confusing. The reasons are manifold, but paradoxically include both an overestimation of the average user’s computer knowledge and a wish to protect the user from technical details that he (supposedly) would not understand. Another common reason is that management is afraid of revealing too much about the implementation of the application by giving error messages that can give clues on e.g. the technologies used.

Many interesting examples of poor error messages, with a focus on over-estimation of computer knowledge, can be found in the Interface Hall of Shame. Below I will focus on lack of information.

Consider the following examples:

  1. File not found!

    This would be fine, but not exemplary, if in response to a user request for a specific file. Unfortunately, I have repeatedly seen this in relation to the normal operation of a software, when an internal file is missing (in particular with Microsoft products). There is no reason to hide the name of the file from the user, nor is there a reason to be so uninformative in general. Consider instead the message:

    The file [full name of file] could not be found. This file is needed for internal purposes, and its absence indicates that your installation is corrupt. Please contact your system administrator or our help desk.

    Now the user has options and feels less abandoned, and the help desk will actually be able to give an advice other than “re-install the application”. Other options include searching for the error message on the Internet (there might be an easy cure available), finding a replacement file, and simply creating an empty file with that name (this has worked at least once for me).


    Addendum:

    Looking back at this text, I suspect that I am overly optimistic about the help desk. There seems to be a systematic problem with businesses trying to minimize any and all efforts for a customer who already has paid, even at the cost of a far larger effort on behalf of the customer. (And even when the business at hand is actually to blame for an issue.) Correspondingly, chances are that a blanket “re-install the application” would follow, even when a fix is possible. That low-level support often lacks any deeper skills and knowledge, often even works based on scripts written by someone else, does not help.


  2. Access denied!

    Here there might be valid reasons to be terse, because a cracker could benefit from extra information as to why access was denied. However, in most cases the needs of the user would be more important, e.g. because cracking is not really an issue in the context at hand or because the information given is not of significant value to a cracker. Consider instead:

    Access was denied. Your current user [name/id] is not authorized to change (/read/delete/whatnot) the object (/file/area/whatnot) [object name]. If you need this authorization, please contact [whomever].

  3. You have not filled out all mandatory fields!

    Clearly, it should not be a secret which mandatory fields were left unfilled; nevertheless, a sizable proportion of all websites simply do not indicate properly which fields were left out. (Some of them do not even indicate which fields are mandatory in advance...)

    Consider instead either of these alternatives:

    Please fill out the mandatory fields age and street number, and then re-submit.

    You did not fill out all mandatory fields. These fields are marked in red below. Please fill them out before re-submitting.

Note: The examples above are not, except by chance, direct quotes; but are representative statements. Whether e.g. “File not found!”, “Could not find file!”, or another variation is used, is immaterial. In particular, I have deliberately not added the typical specification of the application (e.g. “Microsoft Internet Explorer”). Adding them would bring nothing to the clarity of the examples, but would force me to invent names (or mis-associate applications and error messages, or spend time to find literal examples).

In general, a good guideline is that an error message should be either sufficiently informative that the user has an available course of action (e.g. fill in a mandatory field, apply for more rights) or sufficiently specific that it would be a uniquely identifying criterion for e.g. an Internet search (cf. the first example). It is particularly noteworthy that some errors that are beyond the average user, can still be corrected by a power user or computer professional—denying him this opportunity, with the motivation that the mentioned average user would not understand the details, is idiotic.

A particularity is web pages, where there is an understandable wish not to give hints to a cracker, and a ban on displaying e.g. Java stacktraces to the user is very common. A good work-around is to print detailed information into the log file, mark the corresponding entry with a unique identifier (preferably an ascending number or a time-stamp with an extension to ensure uniqueness), and then display this identifier in the error message given to the user. This way the user can give the identifier to the administrators (should the need arise), who will now be able to find the full information in the log files.


Addendum:

My current project (January 2012) contains one of the most idiotic examples that I have ever encountered: More or less any unforeseen error is rendered to the user as “Database error”—including those that have nothing whatsoever to do with the database...

Unfortunately, the error handling, already present when I entered the project, is too convoluted for an easy change and the application has a limited life-time, being written ad hoc for a, by law, time-limited and highly specialized government activity.


Log files

Similar problems occasionally occur where log files are concerned (although to a lesser degree). I recall for instance one manager who insisted that every log message should consist of exactly one line so that he could use some special GUI tool to browse the log files (as opposed to reading the files directly, which everyone else did). As a consequence, we could not include stacktraces of Java exceptions and effectively lost the single most important help a Java developer has in investigating unexpected exceptions. Another issue is improper internationalization, something that prompted me to start the following threade on the apache.commons.dev mailing list in 2002. The ensuing discussion provides several interesting perspectives, and the best solution seems to be to ensure that there is always a language-independent error code present that can be used to pin point the issue or find a translation of the error message into another language than the one originally used in the log (the Oracle DBMS is a good example of how to do it).


Addendum:

During a revisit on 2023-09-03, the above link led to an error page. I suspect that the gist of my take was (and is) that log files are inherently different in nature from interactions in the user interface and that internationalization of log files will tend to do more harm than good—even when the user interface is internationalized.


(I note, however, that logging can include many other things than errors, including trace and info messages. Depending on company policy, there might be several such log messages per method/function. Whether it will be practical or beneficial to have individual codes and translations for all of these seems highly doubtful. The rule would then be either “in English” or “in the language used for code comments”; however, typically, they will be the same.)

Misleading and dangerous messages

One of most misleading and outrageously dangerous messages I have ever received came from the Windows Explorer: I tried to access a drive formatted with a Linux file system–not with large hopes, but “no harm in trying”. No harm? Up popped a dialog claiming that the drive was not formatted and asking whether I would like to format it now!

Fortunately, I had been away from Windows for a long time, and was thus not in the confirm-every-dialog-automatically-without-reading-it mode that I often end up in when I use Windows for a longer time. Had the opposite been the case, I could inadvertently have destroyed everything on the partition by just doing one seemingly harmless click. Similarly, a scenario could very well occur where one person uses someone else’s computer and out of ignorance starts a formatting operation; or one where the user has one unformatted partition he intends to format under Windows and one with a pre-existing file system from another OS, and he is fooled into formatting the wrong one (notably, the drive-letter-to-partition mapping under Windows is very arbitrary, and can be highly misleading); or the user could conceivably erroneously choose the wrong option...

Now, some readers might want to argue that it is unreasonable for Microsoft to consider every possible other file system out there—possibly, they would even be correct. However, I note that just adding code to detect the most common other file systems would not be very hard, seeing that the specifications are usually public (unlike most written by Microsoft). Further, that adding support for other file systems would be a worthy enhancement—much more so than various optical gimmicks. Further, that the error message could easily be made more secure, e.g. “The drive is not formatted with a file system recognized by Windows. There might still be a file system with important data on it. Do you want to format it now?”, in conjunction with an confirmation mechanism unlikely to be triggered by mistake (possibly ticking a check box or typing in the word “yes”).

Notably, the (re-)formatting of a partition is one of the most dangerous things that can be done with a computer—much more so than killing a random process, pulling the plug of the computer without shutting it down first, or deleting a single file.

Too many messages

Too many messages is a common problem, in particular in the world of Windows. As mentioned above, the inflation of the number of messages can lead the user to deflate their value, and to react automatically. Consider the deletion of a file: Per default, the user is asked whether he wants to move the file he attempts to delete to the recycle bin. (How is that for politically correct? How would the files be recycled? Are the individual words of a file broken out and re-used in new files?) This is entirely unnecessary: If the file was deleted immediately then a confirmation message would be in order; however, when a recycle bin is used, an erroneous delete can easily be undone—either use a confirmation message or a recycle bin. (It is possible to turn this query off; however, finding this out, not to mention how to do it, is not trivial for an inexperienced user.)

Another example is killing a process in the task manager: That the default is to query the user if he really is sure, is in order; however, as far as I know, there is no way of turning this query off. I have often killed processes over the task manager; I cannot recall any single instance in which I have unintentionally even triggered the confirmation message. In particular, in the old days of slow single-core processors, it often transpired that an application monopolized the processor, made the computer unusable, and had to be killed. This played out in the following manner (with minor variations between Windows’ versions):

  1. Press control-alt-delete.

  2. Wait, sometimes for more than a minute, until the corresponding choice dialog comes up.

  3. Choose the task manager.

  4. Wait, sometimes for more than a minute, until the task manager comes up.

  5. Tell the task manager to kill the right process.

  6. Wait, sometimes for more than a minute, until the confirmation dialog pups up.

  7. Confirm the killing.

  8. Wait, sometimes for more than a minute, until the process is actually killed.

Without the confirmation, life would have been so much easier; in particular, because it was not always entirely clear which process was the eventual problem maker, and more than one process might have needed killing.

Similarly, many GUI-based applications overuse informational messages in modal pop-ups, which need to be clicked away. In contrast, older Unix-style applications (e.g. editors in the Vi and Emacs families) use a status line for messages: If an informational message is needed, it is simply displayed in the status line, without interfering with the users work and without needing any activity from the user. Notably, noticing such messages is not at all hard, it is just a matter of habit: Someone who is used to this superior mode of displaying informational messages does not miss them. Modal (informational) pop-ups might have some limited value for pure beginners, but they should not be forced upon the more proficient users—a simple toggle in the preferences to move messages from pop-ups to a status line would be immensely beneficial. (Additionally, a status line also allows for more messages: For pop-ups the principle “when in doubt, do not” must apply, so the user is not constantly harassed; for status-line messages, in contrast, “when in doubt, do” applies.)

A prime example of this is a “File saved.” message (with variations): With few exceptions, a pop-up should only be used when the save failed—the success of the save is so typical that it does not need a comment. Further, informing the user when the save was completed is not the job of a pop-up, but of the mouse pointer (e.g. a change from an hour-glass symbol to a normal pointer). Only extreme newbies are unaware of such conventions, and it is not acceptable to make the rest of the world suffer for an inexperienced minority (again, the newbies could be separately accommodated through a toggle in the preferences).

Make sure that all pop-ups (aka “dialogs”) can be closed without unnecessary effort, like moving the mouse pointer or switching from keyboard to mouse. At a minimum, it should be possible to close pop-ups by pressing escape, return, or whatever key is standard in the exact circumstances.

Make sure that error message can be copied!

Always state unambiguously which object could not be found, which record was corrupt, etc.

Make sure that pop-ups of a similar character have the same layout, options, and default action:

For example, with Remedy (the worst ticket tool that I have ever worked with) one can leave a ticket by closing the ticket window or by starting a new search. In the first case, if unsaved changes are present, a pop-up appears stating that there are unsaved changes and asking whether the user really wants to close the window, with a default of “yes”—implying that the changes are discarded by default. In the second case, the pop-up asks whether the changes should be saved, also with a default of “yes”—implying that the changes are preserved by default. Either one is acceptable on its own, but when taken in combination they become very dangerous, bringing a high probability of accidental saves of data that should have been discarded and discardings of data that should have been saved.


Side-note:

Disclaimers on Remedy:

I do not have the opportunity to check the exact details at the time of writing, but the core problem is correctly described.

It is not clear to me which of the many, many problems are caused by Remedy, in and by it self, and which by the (possibly extensive) local alterations by the one organisation where I have used it.


Excursion on unknown information

For some of the more detailed error messages suggested above, the case might arise that certain information is missing, e.g. because, in Java, a generic FileNotFoundException was caught comparatively high up. In some cases, this can be a legitimate reason to reduce the information, as making error handling sufficiently granular might imply a disproportionate effort and/or make the code overly complicated.

However, a datum of such great importance as the file name should always be present—if not, serious changes are needed.

Moreover, such lack of information is often due to lazy or incompetent error handling. Some Java developers, e.g., seem to see Exceptions as a licence to do no internal error handling at all or to do error handling only at the top level (e.g. in a main method). Others seem intent on catching any Exception that occurs and replacing it with a more generic Exception that hides the actual error message, the original stacktrace, and/or the original type of the Exception—or, worse, surround code with a try-catch-[do nothing], which effectively swallows any and all information, including that there was a problem at all. (And, yes, I have encountered several such nitwits.)


Side-note:

It is an arguable best practice to ensure that all Exceptions ever coming from a given package share a common and package-specific parent (possibly, excluding some Exceptions otherwise considered sufficiently well known). This can require wrapping Exceptions that occur e.g. when a method in another package is called—which is perfectly legitimate. The key, however, is that no information is lost. Most notably, the original Exception must be preserved and retrievable from the wrapper. Depending on the tasks associated with the package, it might also be necessary to have several subtypes of wrapper (and non-wrapper) Exceptions. For instance, a package providing a curl-like functionality might include separate wrappers for issues with (a) network IO, (b) file IO, (c) other, or for e.g. (a) local issues, (b) remote issues, (c) other issues.

A try-catch-[do nothing] has some few legitimate uses, e.g. relating to string-to-number conversions in Java. Above, however, I refer to a much more blanket approach. (And even for the legitimate uses, it can pay to find a better solution.)