Error messages should consist of both the input being handled, and what the actual problem was, as precisely as possible. Many (most?) error messages are just of the generic form “an error occurred” (and even that exact message), without any further information.
To illustrate the difference, some examples, from least to most informative:
invalid account data Email invalid Email address invalid Email address in invalid format Email address not in the correct format Email address not in the correct format: foo.bar@baz Email address "foo.bar@baz" not in the correct format Email address "foo.bar@baz" not in the correct format: invalid domain name Email address "foo.bar@baz" not in the correct format: "baz" is not a valid domain name.
User name invalid User name invalid: john gallagher User name "john gallagher" not valid: invalid character. User name "john gallagher" not valid: invalid character: " ".
Quoting the arguments is valuable, especially when they are strings and on the end of a message. For example, the second message below makes it clear that the cause of the error is that there are trailing spaces in the URL:
Invalid URL: http://www.foo.com Invalid URL: "http://www.foo.com "
The principle of being precise means that error messages should not be of the format “x or y occurred”, for example, “The database could not be connected to or there was an error during initialization.”
As a programmer, I can clairvoyantly read that code:
try {
db.connect();
db.initialize();
}
catch (Exception e) {
throw new DBException("The database could not be connected to or there was an error during initialization.");
}
That’s just irrational laziness, leading to user frustration (and calls to support). The basic principle is: give the user the information to solve their own problem.
Coding quality messages can often involve a lot of coding. Therefore the quality of the messages has to be treated like any other feature and have its usefulness compared to its cost to implement.
Errors which are going to happen frequently, like invalid input, should probably get a more thorough treatment. However, for errors which are very uncommon, or which pretty guarantee a support call anyway, there is little value in making them self-descriptive.
I agree that utility should match cost, but I don’t think that these ideas drive up the cost of messages dramatically, especially given that usually errors are detected with code that could be propagated to the user, such as:
public void validateUserName(String userName) throws Exception { Character[] badChars = { '\'', ' ', '*' }; for (Character ch : badChars) { if (userName.indexOf(ch) >= 0) { // throw new Exception("userName contains invalid character"); throw new Exception("userName '" + userName + "' contains invalid character: '" + ch + "'"); } } }My point is that often times errors are simply “dumbed down” with incomplete information going up to the user. I’d prefer that it be transparent.
Of course, this assumes that there is low-level error checking. Alas, it seems that the common practice is for error-handling and -reporting code that is essentially this:
try { validateUserName(userName); validatePassword(password); checkConnection(connection); checkCredentials(connection, userName, password); } catch (Exception e) { throw new Exception("an error occurred while connecting"); }