I try put as much context as possible into my error messages, I serialize the request object too. I think this is because you shouldn't be debugging in production.
The article is not talking about bugs or software errors. It's talking about how programs respond to exceptional conditions like malformed user input, missing config files, etc.
I draw a big distinction between user-facing error messages and dev- and ops-facing error messages.
Back when I was doing desktop GUI apps full time, my standard pattern was to display a terse and readable error message, and provide a link the user could click to bring up a much more detailed error report. The more detailed report was purely for the benefit of tech support, and very, very few users would click it unless specifically told to.
I'm no Web developer, but I imagine the equivalent for a Web app would be to display a terse error in the browser and save a verbose error in the logs.
> I'm no Web developer, but I imagine the equivalent for a Web app would be to display a terse error in the browser and save a verbose error in the logs.
Services like Bugsnag are designed for this use case. You can send them an error message with arbitrary JSON attached (cause of error, but also details on the logged in user, device, browser, etc). And then yes, generally a generic "Try again or contact support" error message presented to the user. It works quite well if/when they do contact support because you can lookup specifically what errors have been triggered by that user.
Of course anything is better than nothing. When I took over this codebase its error handling strategy was "Don't show an error message at all and just keep retrying until it works". Which was fine for transient errors, but a nightmare when something did go wrong: the user report would usually be "the loading spinner just keeps spinning forever", and that was all you had to go on. Nightmare.
One assumes an audience for the error message. Unix definitely assumes expertise. Windows assumes a neophyte. Given that something has gone wrong, the question is the shortest path to a remedy.
I generally agree with this, but making sure your error messages are correct is even more important than terseness. The last example of the article is a perfect illustration of this:
$ cat invalid
cat: invalid: invalid path
An invalid path or a file not found are not the same thing! The real danger is that being too terse and unclear is worse than unnecessary verbosity.
It should just have been File not found without anything else by the logic presented in the article.
However, there are some problems with entire thinking:
- When you are looking into results of larger set of operation (i.e. scripts) you may need more info to easier grasp the context
- Did you see it already ? There is no need for verbosity once you experienced a problem recently (which is what happens most of the time)
The errors deserve both variants, short and terse, just not on the same place (I don't want spams in terminal or logs). Short variant should provide some form of id that can be looked at for more details:
cat(e123): file not found
e123 could be searched in detailed error message document.
Trying to minimize the error message as the implementor is a dangerous game because nobody else will have as much context as you.
Rust error messages are widely lauded because they give context and help, not because they minimize character count.
My priorities for errors are:
- enough context to find the error and possibly further information
- consistent formatting so users can learn pattern recognition. Powershell is much better at this than Unix tools because the shell displays errors
- error message should fit on one screen and little but the relevant error should be printed after an interactive command
Terseness is mostly relevant for non-interactive use such as log files that need to be read quickly.
While I'm not disagreeing, there's more: if you are likely to see the error many times it should be short (compare with the variable name length). I think "command not found" is by itself a pretty good message because it is clear and so frequent that deserves a short message. But if it occurs in the middle of a shell script I would like to have the offending line as well.
Meaningful, detailed error messages are one of the core features
of a compiler as the developer needs as much info they can get
to find and fix the problem. But when you call e.g. the
mentioned `cat` command as a user you don't care in what
function it encountered an error and the context leading up to
it, you just want to know what went wrong, unless maybe you're
about to file a bug report.
Also the Rust compiler's output quality isn't due to the length
of the output, it's just formatted very well and has often very
useful hints thanks to the compiler's insight into types and
ownership. In the world of NodeJS, TypeScript etc. I've seen a
fair share of verbose error messages, mostly consisting of
worthless but colorfully formatted information that only makes
it harder to find the actually useful part.
> For one thing, repeating the entire search query in bold isn't necessary.
I hugely agree with the thrust of this article, but this Google example might be a mistake to include. It’s the only lay-person example here, not a shell or programming language for technical people. Showing a Google query back to a user, I might speculate, has an important function of allowing users to see spelling errors they didn’t know they typed. I can imagine other reasons as well, and I’d be willing to bet that Google has tried both and decided on repeating the output. The other thing not discussed is the Google output is organized hierarchically, separating the error from the tips, and bolding the search query. Those two things could dramatically improve the PowerShell output, for example, without removing any text. No other example had style formatting, and good styling and layout can be as effective as silence.
Not only that, but sometimes you issue search then go to another tab, to issue another search... remembering your previous search exactly for N tabs isn't that nice.
>And even in "normal" applications -- where the majority of users are not knowledgable enough to know that their spelling could be to blame -- an error message that's too verbose is still problematic, because many, if not most, non-techy users won't bother reading it!
Assuming users are 'too dumb' or 'smart enough' sounds like a broad generalization that's highly dependent on the tool.
I'm glad we have verbose compiler errors, and I write C++ for a living. Am I too smart for verbose output?
My grandmother can't login in to Facebook, should we forego the error dialogs because she's not going to read them?
I believe that terse error messages have their place, but this article over generalizes and is full of personal preference rather than data driven conclusions.
A note on cat: on older Unixes (I remember it specifically in some old version of solaris), you can actually cat folders, and it will show a directory listing. Iirc in the orogonal unix, read() on a directory fd would just dump out some filesystem internal structs that detailed the folder's contents.
If people see a wall of text, they (from my observation) tend to skip it and conclude that the thing "just doesn't work". Even if the error is explained. So in that, they have a point. A little related are overly elaborate efforts to be cute and cheer up the user on error. (This of course happens more in Web GUI than in command line.) These can be infuriating and make one wish someone expended all this effort and money to actually make the thing work, instead of lecturing me not to get mad, with pictures.
But I think terseness is an imperfect proxy for clarity. In the Google search example, repeating the search query to the user may be actually useful. They may have pasted something by accident and/or heavily mistyped and not even have noticed. Do include important information, so the user can go directly to the place of fault. State what is wrong and try not to have the same message for many unrelated errors.
By the way, I'm still waiting for an "Unreasonable effectiveness of X considered harmful" article.
Strong agree. One of the things that turned me off of Elm, which is famous for having useful error messages, is the cutesy anthropomorphic style they are written in.
More thorough error messages can be good, but they need to be well formatted to help people's eyes lock on to the core message; then they can read more if they need to.
One thing I like about Python's error messages is that, even though you can get a long trace, the most specific/relevant information is usually at the bottom, right next to your prompt. I tell me students, "read your Python error messages from the bottom up."
The bottom-up nature of Python’s exceptions is also handly if you’re running a Python thing in a terminal, or are running `tail -f` on its logs. Java, on the other hand, puts the important bits at the top, so if your tracebacks are long and your screen isn’t too tall, you’re forced to scroll up.
cat is just passing along the error string from the libc/system call it used. That error string is standard-ish over most libcs; some unixs can read directories as if they were files.
Changing that message would require significant additional complexity in cat which probably isn't useful.
I like the approach that ShellCheck uses for its verbose error messages. Every error message is identified by an easily-googleable error ID that is not translated and there is a link to the shellcheck wiki where you can find an in-depth explanation of the error and possible ways to fix it.
For example, a typical run of shellcheck might look something like this:
~/test> shellcheck blah.sh
In blah.sh line 2:
echo $1
^-- SC2086: Double quote to prevent globbing and word splitting.
Did you mean:
echo "$1"
For more information:
https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
I largely agree with the general point, but in the SSH example the “Continue?” is too terse, because it’s not entirely evident what “continuing” will do in that situation. “Connect anyway?” would be much better.
It would be great if there would be a way to interactively “expand” error messages on the command line, in the sense of progressive disclosure in GUIs. Meaning that you could for example have Help/Technical Details/Stacktrace buttons. Or you could interactively expand an error to -v or -vv verbosity level.
In logs this can be partially achieved by logging additional details with a low logging level. With errors coming from exceptions in particular, I like to log the error message (exception message) separately from the stack trace for that reason.
Strongly disagree on the SSH example. Security warnings should be a little more alarming than just "Continue yes/no".
Asking whether they are sure they want to continue has added context to make someone think twice about whether they are really connecting to the correct host.
Likewise, repeating the host address again after confirmation makes an error more likely to be spotted if it's off slightly (think along the lines of spaced repetition helping memorise things).
> For one thing, repeating the entire search query in bold isn't necessary. The user already knows what they searched for.
Echoing the input is useless. But if the program is interpreting the input somehow (like there are keywords or commands allowed), then showing the user what the program understood could be critical to finding the problem.
The argument of "the user" is similar to that for "the web user" where web design is mostly about not making people think. You want them getting to what they want as fast as possible, so no reading, no extra activities, get them to their goal... because that usually means a transaction.
In this case, we should also get the user to their goal. Which is different from that of a web user. The goal here should be to give the "user", which is mostly going to be a developer or someone trying to perform an action, the best possible info on how to accomplish that action and what went wrong the time before that.
So that they can see what needs to change immediately and there should be no 2nd time with yet another error message.
The context is different, but both approaches are about best serving the user in their respective context.
The article and programs make an assumption that I disagree with: That there is only one appropriate way to output error messages.
This is an absurdity. Both methods are valid. Different people want different things from the error messages.
This is most commonly addressed in programs using "verbose mode", often with multiple levels of verbosity ( -vv or -vvv ).
Another type of error message which I wish was a required standard is to output structured error messages in the form of JSON containing all the relevant bits of information. It is very annoying to have to parse apart error messages coming from a tool being called programatically.
On the other hand, I try to run `brew update` and see nothing for 30+ seconds. I wonder if its hung up? Nope. There is absolutely no indication to the user what's happenning behind the scenes. I tried filing an issue and the brew maintainers closed it in record time without explanation. Verbosity helps when it's done right.
36 comments
[ 3.4 ms ] story [ 82.4 ms ] threadBack when I was doing desktop GUI apps full time, my standard pattern was to display a terse and readable error message, and provide a link the user could click to bring up a much more detailed error report. The more detailed report was purely for the benefit of tech support, and very, very few users would click it unless specifically told to.
I'm no Web developer, but I imagine the equivalent for a Web app would be to display a terse error in the browser and save a verbose error in the logs.
Services like Bugsnag are designed for this use case. You can send them an error message with arbitrary JSON attached (cause of error, but also details on the logged in user, device, browser, etc). And then yes, generally a generic "Try again or contact support" error message presented to the user. It works quite well if/when they do contact support because you can lookup specifically what errors have been triggered by that user.
Of course anything is better than nothing. When I took over this codebase its error handling strategy was "Don't show an error message at all and just keep retrying until it works". Which was fine for transient errors, but a nightmare when something did go wrong: the user report would usually be "the loading spinner just keeps spinning forever", and that was all you had to go on. Nightmare.
One assumes an audience for the error message. Unix definitely assumes expertise. Windows assumes a neophyte. Given that something has gone wrong, the question is the shortest path to a remedy.
I was reading through the article waiting for the connection to eloquence and was disappointed when minimalism was in its place.
However, there are some problems with entire thinking:
- When you are looking into results of larger set of operation (i.e. scripts) you may need more info to easier grasp the context
- Did you see it already ? There is no need for verbosity once you experienced a problem recently (which is what happens most of the time)
The errors deserve both variants, short and terse, just not on the same place (I don't want spams in terminal or logs). Short variant should provide some form of id that can be looked at for more details:
cat(e123): file not found
e123 could be searched in detailed error message document.
My priorities for errors are:
- enough context to find the error and possibly further information
- consistent formatting so users can learn pattern recognition. Powershell is much better at this than Unix tools because the shell displays errors
- error message should fit on one screen and little but the relevant error should be printed after an interactive command
Terseness is mostly relevant for non-interactive use such as log files that need to be read quickly.
Also the Rust compiler's output quality isn't due to the length of the output, it's just formatted very well and has often very useful hints thanks to the compiler's insight into types and ownership. In the world of NodeJS, TypeScript etc. I've seen a fair share of verbose error messages, mostly consisting of worthless but colorfully formatted information that only makes it harder to find the actually useful part.
I hugely agree with the thrust of this article, but this Google example might be a mistake to include. It’s the only lay-person example here, not a shell or programming language for technical people. Showing a Google query back to a user, I might speculate, has an important function of allowing users to see spelling errors they didn’t know they typed. I can imagine other reasons as well, and I’d be willing to bet that Google has tried both and decided on repeating the output. The other thing not discussed is the Google output is organized hierarchically, separating the error from the tips, and bolding the search query. Those two things could dramatically improve the PowerShell output, for example, without removing any text. No other example had style formatting, and good styling and layout can be as effective as silence.
Assuming users are 'too dumb' or 'smart enough' sounds like a broad generalization that's highly dependent on the tool.
I'm glad we have verbose compiler errors, and I write C++ for a living. Am I too smart for verbose output?
My grandmother can't login in to Facebook, should we forego the error dialogs because she's not going to read them?
I believe that terse error messages have their place, but this article over generalizes and is full of personal preference rather than data driven conclusions.
But I think terseness is an imperfect proxy for clarity. In the Google search example, repeating the search query to the user may be actually useful. They may have pasted something by accident and/or heavily mistyped and not even have noticed. Do include important information, so the user can go directly to the place of fault. State what is wrong and try not to have the same message for many unrelated errors.
By the way, I'm still waiting for an "Unreasonable effectiveness of X considered harmful" article.
More thorough error messages can be good, but they need to be well formatted to help people's eyes lock on to the core message; then they can read more if they need to.
One thing I like about Python's error messages is that, even though you can get a long trace, the most specific/relevant information is usually at the bottom, right next to your prompt. I tell me students, "read your Python error messages from the bottom up."
cat is just passing along the error string from the libc/system call it used. That error string is standard-ish over most libcs; some unixs can read directories as if they were files.
Changing that message would require significant additional complexity in cat which probably isn't useful.
https://www.man7.org/linux/man-pages/man3/errno.3.html
The author's arguments might work if there's some obvious place to go for more information. I'd take "invalid path: check ~/cat_error_log for more."
For example, a typical run of shellcheck might look something like this:
https://github.com/koalaman/shellcheck/In logs this can be partially achieved by logging additional details with a low logging level. With errors coming from exceptions in particular, I like to log the error message (exception message) separately from the stack trace for that reason.
Controllable verbosity is best practice. Quiet defaults are nice though
Asking whether they are sure they want to continue has added context to make someone think twice about whether they are really connecting to the correct host.
Likewise, repeating the host address again after confirmation makes an error more likely to be spotted if it's off slightly (think along the lines of spaced repetition helping memorise things).
> For one thing, repeating the entire search query in bold isn't necessary. The user already knows what they searched for.
Echoing the input is useless. But if the program is interpreting the input somehow (like there are keywords or commands allowed), then showing the user what the program understood could be critical to finding the problem.
The argument of "the user" is similar to that for "the web user" where web design is mostly about not making people think. You want them getting to what they want as fast as possible, so no reading, no extra activities, get them to their goal... because that usually means a transaction.
In this case, we should also get the user to their goal. Which is different from that of a web user. The goal here should be to give the "user", which is mostly going to be a developer or someone trying to perform an action, the best possible info on how to accomplish that action and what went wrong the time before that.
So that they can see what needs to change immediately and there should be no 2nd time with yet another error message.
The context is different, but both approaches are about best serving the user in their respective context.
This is an absurdity. Both methods are valid. Different people want different things from the error messages.
This is most commonly addressed in programs using "verbose mode", often with multiple levels of verbosity ( -vv or -vvv ).
Another type of error message which I wish was a required standard is to output structured error messages in the form of JSON containing all the relevant bits of information. It is very annoying to have to parse apart error messages coming from a tool being called programatically.