Write better error messages
wix-ux.com
wix-ux.com
A series of Messages and Codes books is supposed to list every message, each with an explanation and suggested user, administrator, or programmer response.
This was more important when messages were practically limited to a single line on a CRT or teletypewriter, and customers had only the printed or microfiche documentation, not online help or websites, but it’s still valuable today.
Now get off my lawn!
On the flip side, if you're willing to give up globally unique for "unique enough within and reasonable time frame" then you can go with just a few characters or even short words.
UPS owes that reddit user a beer for helping out at least 30 people (by up votes) at zero cost to themselves.
Some bad examples (both from Microsoft): - "Code -4" (putting a minus in front of a word makes Google exclude that word from results), - "0x00071153" (search engines love to omit the 0x and give you a bunch of phone numbers instead)
* Say what the program was trying to do.
* Make the message unique and searchable.
* Make it detailed.
* FFS, include the filename or whatever else the program is having trouble with.
* If possible, include the source code location.
* If possible, include useful contextual information.
* Quote strings. Once in a while, some unexpected whitespace sneaks in somewhere and this can be hard to figure out.
Eg, don't just abort with "Open failed: NOT_FOUND". Abort with "job.c:2105 Failed to open job description file '/var/spool/jobs/125.json' when processing job #5 for user 'alice': NOT_FOUND".
This way I don't have to strace the damn thing to try and figure out what's it looking for, and know which user it was for, so I don't have to dig around and try and figure out which entry in the database might contain the wrong information.
Also, context-free, generic error messages are awful. A large enough codebase may be impossible to search for some very common keywords.
If possible, googleable error codes are great to have, but they shouldn't replace the error message. It's ideal if you can search the source code and instantly find where the error message originates.
In terms of "fail early," my larger programs have a section called Pre-Flight Checklist, which looks for files (and that they are files), databases, that the databases have the expected tables and the correct columns, and so on. Are the files sufficiently recent? More or less the expected length? Because this is ETL stuff, it's usually okay to push this stuff up as early as I can.
It's easier to search and store in an incident management system.
Ie all the meta/log context in a hashmap alongside the error message.
That said, Ppetty much everything you're suggesting was considered a bad idea (for security). Mainly because the more details you give away, the more a hacker can understand about the underlying system. The more they probe and possibly break things, the more you're showing your cards.
It was then the bland cryptic error msg made perfect sense to me.
I'm talking here mostly of user-facing local applications -- like what would be in your mail client's logs, or the logs of a corporate service, where the logs are there for the admin's/dev's use.
Of course if you're sending feedback to a potential attacker things change considerably.
Sec = better safe than sorry.
So if you must show a stack dump:
- don't put in lots of whitespace - it might look pretty but it makes it harder to read/parse.
- if you're giving the error file:line, don't bother showing the source code. If the source is meaningful to the reader, they've probably got access to the code, or are using an IDE.
For users they need brief, is it fatal (restart) temporary (try again) or just this part - do something else.
Adding words is unhelpful. More information means less communication.
The reasoning was that "users can't do anything with information we tell them anyways", despite the overwhelming number of help desk tickets we'd get from "Oops!" appearing in a million different scenarios with no clear way for us to tell what error actually caused the message to appear.
Users naturally report the messages that they see because they're helping us to see the problem. I didn't get why that was such a hard concept to understand
That said, this is an easily solved problem. The best solution is to aggressively log errors AND prioritize having dev teams push that error count to 0. If an error happens, it's a bug.
The next way to solve it is simply a report button. Let the users click a "I'm mad at you for not working" button and embed something like a session ID that allows internal queries into what went wrong.
Error codes are a terrible solution, but perhaps an OK option if this is not hosted software. That said, a more user friendly approach would be a QR code with all the relevant details embedded.
Nope. Useful messages contain details about what your software does. Anything about your tech stack is redundant and can be removed.
> The best solution is to aggressively log errors AND prioritize having dev teams push that error count to 0.
Many errors can only be replicated talking to users. And on the cases your dev team is not all capable enough to remove all errors, you will still want to provide customer support and work-arounds.
> The next way to solve it is simply a report button.
A report button is good. But neither session ID nor any data that you can reasonably add to your logs will be enough to let dev know what went wrong. Besides, your report button will have errors too.
And anyway, anything that you said applies exclusively to people that create web applications. Many other types of application exist, and everybody writing them are better off not following any of your recommendations.
Having a unique ID to be able to search in documentation or even source code is -IMO- preferable. It's still rather technical and helps only those who can search such docs, but at least it gives something unique to google/search for."
Until one day you find some random dev is logging failed authentication attempts and including the email and password in the logs…
(and the most amusing part of that incident was tracing down the offender by finding the earliest of those particular log lines, and getting his real email address password out of them… “Hey Phil, what’s ‘Dragons87!’?” “Ummm, what? That’s, errr, my gsuite password. How did you know?”)
All the others wanted to hide the reason because "if we know the reason and tell the user, we seem incompetent" or "then hackers will know which API call isn't working right" (apparently the network console in Chrome is beyond hackers) to wanting customers to be dependent as they paid for support.
I mean, I feel like the focus of the OP was on giving them something they could do something with. Like the information that their information was not lost; and the recommendation to change X or try again in Y way; and the fallthrough to contact customer support with a quick link.
The OP was definitely not recommending giving more specific technical info without thinking about what the user could do with it, but instead specifically thinking about what hte user could do or would want to know (about their data/account, not about your under the hood services), and giving info to that end.
At least a "Details" button to unmask the technical details would be useful in some way, while hiding the "ugliness" to the end-user.
When I tried to install Acrobat on my Mac, I got this message:
"Your hard disk is too small"
My what is too small?!
Later, on Windows I got this unexpected popup:
"You are not here"
WTF?
I searched the code for that string and found it in a function named "CantHappen()". This function was called in numerous places where the programmer thought there was no possible way for the code to get to that place. But of course CantHappen() did happen.
As I looked through the code I found many other messages that were bizarre and incomprehensible and sometimes downright offensive.
So I started a project to go through all our messages and make them more clear and informative - and even better, when possible to not have the message at all but just take care of the situation.
The underlying cause of these bad messages was twofold:
1. Programmers never got raises for writing great error messages or finding ways to avoid them in the first place. We were just rated on how much work we got done.
2. We did have a product designer who was supposed to specify all user-facing messages. But the designer mainly considered the "happy path" and didn't think about edge cases. It was left to developers working under time pressure to handle those.
Rust funny enough has unreachable()! for that case, but it also has unreachable_unchecked() for actually unreachable code. The latter has undefined behavior and exists to help the optimizer.
The usual argument is that the program would be in an invalid state if the condition was reached, so the only option is to crash. If it turns out it's a valid state, then the programmer can treat in a branch. I don't think tests would capture this because they would operating under the same assumption that such states cannot exist. Maybe fuzzy testing could surface an issue like this.
I stripped it out before production after verifying it couldn’t actually happen but it was something like an artefact of my thinking process while writing the code.
It feels like a kind of assertion of underlying assumptions, and I know enough to know I’m fallible.
I’m always careful to make the error message something reasonable if it ever did actually come up in a tech demo or something though. Anything else is tempting the Fates.
I’d always make it something like “If you see this, something entirely unexpected went wrong.”
Showing and triggering the error is helpful in itself since it’ll generate a trace and all the attendant stuff.
The absolute best I had in a Microsoft product was this (paraphrasing): "An error happened because your computer may be turned off". I still have a screenshot of that somewhere. What it meant was that an hypothetical computer I may be trying to connect to (which I wasn't, it was all local) was off, but that wasn't the case. This was seriously WTF.
The second most beautiful one from another Microsoft product was whatever software generating a password and asking me, in a pop-up window, to write it down. The problem was the password was something like:
9mZOvy9E(4)?6b(w(<$KcTU%>9T6cz0Z4YxgQ-<tw035X6S.dLE0[2n0"42`/S=S1{q5{)61s190':&6UHT.4hZXjO6b%l#X7v]~4tIT2Y0._ebFH,>2:G>%*P]7n4"
I probably also still have a screenshot of that somewhere.Haven't used Microsoft stuff in two decades so it was a long time ago. But it's still seriously WTF.
…which is the text for result code zero, which is used to mean “no error”.
"Fail early, fail hard"
i.e. if I can make the error message happen near the beginning of a process, I can get away with making it a hard error.
Hard errors in the middle of a multi-hour operation tend to annoy people.
Users don't care if you consider an error soft or hard.
It's implied that it would be the upper top-most exception handlers in that code path but those are gonna be more generic in their messages, and anything more detailed has to be manually wrapped to add useful description (that's not some internal developer exception).
Error codes may be the least bad solution, to fallback on.
Error messages are part of the user experience and they should not be an afterthought.
If errors are nested, list them all. Give a generic feedback then, and also provide a technical explanation that would help debugging. Most importantly, we should make the user feel safe and in control as much as possible.
Works great for things like validation.
As opposed to 6 months down the road when someone finally notices an uptick in complaints by customers and now the potential problem sites is literally the entire software stack.
fail fast is how stable software is made, the question is whether or not you think customers appreciate stable software.
I guess this is because no one really teaches error handling. I assume a lot of students end up with a mindset of just make the errors go away instead of, deal with the errors effectively.
A lot of `if (input == null)` checks are because you're just not sure whether the argument being passed in will have a value, and it's too much work for your small feature PR to refactor the whole codebase to resolve it.
Use typescript/python-with-mypy/haskell/rust/whatever and this problem mostly disappears.
Null checks are totally fine, but it should be clear whether or not null is a valid input to the method. If the answer is 'no' then you should throw ArgumentNullException (or whatever's appropriate for the language), not silently ignore the bad input.
Otherwise people start e.g. checking in the frontend and don't enforce it in the backend in the worse case, or TOCTOU bugs in the best case.
In the past month, i’ve had about a dozen interactions like this:
developer: your service crashed, here’s a screenshot of the last 5 lines of the crash
me: do you see where the final text you just pasted is “RuntimeError: Did not find ENVVAR, ensure this is set to the proper value (see <internal wiki link>) and then restart this service”
developer: yeah?
me: well, did you do that thing?
developer: what thing?
me: <headdesk>
and this at work, where the developer in question is intimately acquainted with the context and purpose of the project.Notice the direct language. It reads like an order. The less direct the message, the higher the chances that the user will not act upon it.
Can you help me understand what isn’t clear about the message as is, or maybe point out the ambiguity to someone who just isn’t seeing it? I want to write better error messages but I share the frustration of the above poster. The message tells you specifically what to do, but you’re coming back saying it’s not clear.
Not OP but I've noticed that people often get brain fog when something goes wrong and are often need BIG, SHORT, WORDS to shake out of it. Or really anything that can shake them out of the 'idunno' state of mind.
But maybe if something like that became standard ut would no longet be a context switcher..
It's easy to say "they can figure it out". Sure, in a restful state. But the people we're asking to take action already have a lot on their plate. Using plain, conversational language whenever possible with exceedingly clear steps means less mental exertion on the receiver. And since we need their help, anything we can do to make it easier on their end helps us.
For someone who was born speaking English and spoke it their entire lives, the example provided couldn’t possibly be more to the point in my opinion.
Though I agree overall with the general idea and that yes there are some pretty baffling and downright awfully written error messages and log entries that take a minute to grok (I just don’t think the example replied to is one of them).
Error in file foo/bar.c, line 32, missing semicolon.
No conversation needed. These can then be complemented with more conversational language on the next line to explain why semicolon is needed. Rust is quite good at this.Really, should logs also be documentation now ? Just mindlessly logging the same "advice" over and over again each time the error happen ?
Not even to mention the fact that new or changed error messages caused a landslide in costs in translations to various languages. I guess this product has no localization? At that time, when I was working at such a product that had it, we had to go through a deliberate process to describe why we want to change it, what the impact is, etc. Tell me you want 100 new messages and you will be stuck in meetings for the next month.
In their case, though, it seems they at least have the support in management for it. I hope it turns out better for them than it did for me.
I write software that is generally run low in the stack, quietly doing some mundane tasks that are business-critical but rarely thought about. If one of our clients has to mess with our software beyond the occasional update, that was a failing. Not all software is like this, but lots of it is -- its value is that no human needs to be involved.
I need to write log messages with the expectation of an audience who doesn't know much about the software -- it's been running uninterrupted for months or years and suddenly something has gone wrong. If the log line doesn't tell the user how to solve their problem, I will end up getting a call.
No, the most best thing is to point to the documentation which has that, and not printig out manpages of docs in error messages now.
> I write software that is generally run low in the stack
What stack, how low? Me too.. that low that I usually cannot return or even log a " see error code doc at http.." string for various reasons (bandwidth, mem, performance) but only have error codes ;)
If I'm starting a service and see a pointer in the logs to documentation, that seems like an incredibly broken approach to me. Why would I look at missing or out-of-date documentation that may or may not be at hand when the code that knows the problem is right there and can just tell me? A log message like you're describing might as well say, "Something went wrong, but I don't want to tell you what. Instead check page 43 of the document in the third file cabinet from the left in that room over there on your right. No, your other right."
> Something went wrong, but I don't want to tell you what.
is somewhat disingenius of an example. Error logs should tell in exhausting detail what went wrong. Ops needs that to analyse the situation, and the vendor will have much less trouble reproducing the error. However, suggesting specific fixes could be disastrous. Furthermore, documentation should already be in a form that operations can be expected to work with also in crisis situations.
So why not provide docs on how to solve the error along with the error.
If it's in the early lifecycle, absolutely, because it's most actionable. X is set wrong, Y can't be reached, etc, guide whoever is operating the system how to fix it.
If it's mid cycle, it's often post-hoc, but context is worth its weight in gold. Less about telling the operator how to fix and more about why it broke, to avoid in the future.
End of cycle, whatever.
In other words, yes.
Remember that often the person reading the logs is not the person who wrote the software. Maybe it's an Ops person at 2AM trying to fix a broken deploy. Maybe it's a developer who joined the company 3 years after the software was written. Maybe the log is passing through an error message from 3 layers deep in the stack. The more literate your logs are, the better.
There are people who don't read formal documentation but do read logs, after all.
If the advice is the same over and over again, then yes, give the advice over and over again. I wouldn't want to assume that someone has read every line of the logs, or has started to read top-to-bottom, so the advice should always be among the most recent lines in the log, and the only way to ensure that is to give the advice again each time the error happens.
The clarity of the error message doesnt really matter if the recipient believes it is intended for somebody else.
I feel there's a trend when it comes to disseminating messaging like this that we adopt an attitude of our audience "is smart, and should figure the rest out". They may be. But they already have lots to do any plenty to figure out. Any opportunity we, the requestor, can lighten their mental load, is going to increase the odds that they'll be inclined to take action right away.
The example given was clear compared to 90% of other error messages, and saying that it needs to be "more clear" is almost dismissive
Many people just lock up when software doesn’t do what they expect.
The problem can come when there's a wall of "useless" logging/error messages, and the last one or near the last one is the actual important one to look at. You have to explicitly call it out on a clear screen and make it obvious - and even then, people won't always read it.
Adding a URL might not be a great plan, never know how long an old copy of a program will stick around, might not control that website forever.
Which can be tricky, because the degree of negative feedback that is appropriate to the person in question can range from
"Polite one-on-one suggestion that you read the error message more than once before calling me"
to
"Full on yelling at the person in the middle of an open-plan office".
Thankfully, type II is rare, but they do occur.
I'm really lazy: if I were on the receiving end of emails with error messages that included instructions about how to fix said error I'd automate Freshdesk (or whatever ticketing system I was using) to respond with instructions specific to that error message, in the first instance, along with a note to get in touch again if that didn't solve the problem. I'd also set the ticket to autoresolve after a set period of time.
If a web app pops a well written error it is much more likely to be acted on than an unmotivated dev seeing a some (probably badly formatted) text.
Every time I see an error in terminal with a link to documentation I'm delighted. And surprised.
Are you wrong for skipping documentation? Yea, maybe. Is it entirely expected? Yea.
Based on the parent comment, at least.
What could it be? Why do people read things and react in similar ways, even if they have different jobs? If only there was some field of study that could answer these mysteries.
> Hi! If you're reading this message, it's likely because this tool failed your build. To understand why and fix it, please click this link <link_to_internal_doc>. Below is a table that lists the packages you need to update and the version you need to update them to.
The doc had at the very top in big flashing red text with siren anigifs a link to the portion that explained that they needed to update their libraries with very clear copy-paste-into-Dockerfile actionable guidance. The page also explained the broader context, such as the point of the tool and why we were doing this despite having a firewall and so on.
This is where you might be delighted and surprised.
What was perhaps less delightful and surprising were the consequences for me. About 4-6 times a week, I would then have a Slack conversation akin to this:
Dev: Why did you break my build!?!
Me: Can I see the error message?
Dev: <pastes message above>
Me: Thanks! Looking at the message, is there something unclear about the documentation? Does it not work?
<ten minutes pass>
Dev: Nope! Docs are great!
At this point the conversation would end.So your error message while a far cry from the worst I have seen is also pretty far from the good ones I have seen.
Reaching for the easiest way to solve a problem first is a very human thing to do, and in this case he was easier to contact than opening up a browser and reading an article that presumably is written in the same kind of language as the error message.
Asking as someone who otherwise generally agrees that there are some truly poorly written errors and exceptions out there, but has also been on the admittedly frustrating end of the constant requests for help deciphering error messages that were very plainly stating what the problem is for someone who didn’t even try looking for the fishing rod.
Few error messages are written well, has good formatting and are self contained (can be used to fix the issue without having to seek further information elsewhere). Sometimes you see errors that contain one of those elements, but rarely all of them.
There has been an effort the last few years improving compiler errors for some languages, but those same improvements have not reached applications.
If the volume of drivel was lowered and errors were formatted with spacing and color to stand out, then they would be easier to focus on.
So log errors to stderr, send it to a separate log file, and format it well (use multiple lines).
Oh, for sure. Do never:
- send errors to the same log you send normal activity.
- default into logging things that aren't errors on the error log (make this possible to override if you want, but never the default).
- log the errors there, but the necessary context on stdout so it appears correct on a terminal. (E.g. build tools that print entering into target in stdout; error in stderr; leaving target in stdout)
- try to recover just to show a different error later.
But, it also logged each and every occurrence of this at "Error" severity, instead of at "Info" severity (it is, after all, expected to happen once in a while).
And of course, once our code switched over to using this, the first few times every team member had to deal with a production issue, the immediate reaction was "oh, no, the data store is unhealthy! look at this mass of error logs, I can see one every few minutes!". Thankfully, after the first team member (me, as it happens) spent half an hour reading the relevant parts of the design and implementation docs, we could frequently short-cut a lengthy investigation by "oh, you think $DB is bad because you are seeing transaction failures? no, that's expected, see $URL".
I just had an idea: Put tracking info in the error URL. If your company has an internal URL shortener, that could do the trick.
More practically, I feel like it helps to put an empty line before the call to action. For many people, a traceback is just noise. The empty line helps split the useful info out from the traceback.
Or if it's a script/CLI (and you know the error reason) don't even show a traceback. Just print the error message to stderr, exit non-zero, and be done with it.
I'm laughing as you could not make it clearer if you tried. PEBKAC
Get a screenshot or the exact verbatim of it, and you can identify exactly where in the code it originated.
User reports are unreliable, but when I can pinpoint where the message originated from, it massively cuts down on the troubleshooting time.
A good way to take advantage of that is to have a central database of all error types, but not many companies bother to do that.
do you have any example?
Users, upon hitting an error, often go check Stack Overflow. If you localize your error messages, you Balkanize the collective wisdom on how to address the error (which will always be larger than your team's ability to troubleshoot errors and offer correctives in your documentation and FAQs).
The Typescript team does this with compilation errors, like `TS12345: frobulating types cannot be transmuted`.
If only I had a penny every time someone sent me a “log of the error”, that only contains the final line with the unhelpful message saying nothing but KeyError.
I've met multiple "web developers" (actually working on the backend or "full-stack", building API servers and whatnot) who came complaining about this or that server being "unreachable" and could I check it's up / whether the firewall allows them through. Only to find they were getting HTTP 404 errors or the like. Which were explicit in the errors they'd show me.
Then for years almost without fail when an error was pasted into a GH issue it would include the big "If submitting a bug report, please include the full stack trace at /var/log/stacktrace.out" message--without the stacktrace. I added some whitespace around it and all caps to it and still nobody read it.
I wish I had learned that earlier than I had.
Include random numbers. "Error 7743929" is super easy to track down (grep -r 7743929 takes 2 seconds to type), you don't need a NATO alphabet to understand what they're saying on the phone in order to be able to search it correctly, its general purpose is understood internationally, and it won't change between versions (like when you'd encode a file name and line number, for example). When I first figured this out at, idk, 17 years old and mentioned the idea in a game making forum, people called me crazy, but I still use it and don't know of any better system.
Of course, this is alongside an actual error message to help the user help themselves. This is just to trace the line where it originated, which already helps a lot for small software projects like I make.
I have no idea how these people get through life at all.
For example when someone asks me "how do I get a German work visa" and I reply with a link to a page titled "how to get a German work visa", which is the among the first results on Google. A literal minute later, they ask me more questions that the page clearly answers.
Some people can't be arsed to read a 5 minute article you hand-delivered to them, and would rather have you type it back to them.
I think that some people just have zero respect for other people's time.
The fact that you've had this a dozen times points to a problem with the app more than the people using it to me.
Why is the user like this? Error message PTSD. Years of staring at obscure errors full of technical jargon that are not helpful to the user, has left them scared to even look at the content of the error message. They have tried to Google these things before and failed, and now they just avoid it entirely and run for help.
I'm sure there's enough detail in the link you provided to help the user. But if that's the case, it will be better for the error message to simply say:
A problem occurred, but don't worry! You can fix it yourself in 5 minutes! For instructions, visit https://internal-wiki-link/spaces/BLAH/AppUserRuntimeError#A013579
Even if you expect the user to be "smart enough" to fix their own problem, they are more likely to try it themselves if you make it seem easier.Going out on a limb, I think we're all going astray by trying to parse the error messages our fellow developers are reacting to. A great many seem to handle any unfamiliar or unexpected error message by giving up, no matter how friendly or informative or helpful it may be.
They learned that the affordances of these error messages are copy pasting into some place: a google search box, or a chat box asking for help. But it has no affordance of "interpret as an English sentence" for them.
Unfortunately, it is perhaps not an ideal fit. I was mostly not dealing with the most junior and new of developers here. I was often dealing with senior developers who fully understood that they were responsible for investigating their own issues in a context where it was understood that troubleshooting takes time.
I often wound up regurgitating the error message back to them, asking them to point to the problems in the documentation getting in the way of them solving their own problems. This generally resulted in a conspicuous silence and the issues shortly thereafter being resolved.
The lesson I drew from this was not that the developers in question needed training. What I learned was that they needed to be convinced to treat these errors as natural-language strings they could interpret themselves.
Some people develop the same with relation to error messages because most of them are not actionable, other than "stuff broke somehow, [gibberish] blabla". Even if your error message is impeccable, it's in the class of things that are noise.
If you come up to me at some busy tourist location, where I'm used to lots of scammers, I won't listen to you even if you are actually a nice person and just want to have a nice chat and we would be compatible friends.
Often it is a good strategy to just ask people. Documentation and comments get out of date very fast. If you are the kind of person who reads everything meticulously and googles around, reads manuals etc. you may be wasting a lot of time. Of course there is a right balance to find. Some people err too much on the side of not thinking themselves and immediately asking for handholding, but overall it's often the right thing to do.
In many cases I found that trying to reason out what was going on was hopeless, because when I eventually gave up and asked someone, it turned out that the solution was unguessable, something like "ah of course, that things is out of date, do this magic incantation, then this and that, yeah we should update the docs sometime!".
A lot of knowledge is locked up inside people's brains and just spreads around as "rumors" on the grapevine. Is that state of affairs ideal? No. But it's realistic and people are going to adapt by asking first, thinking second.
I had this recently. Many individuals like to play hero and make sure I don't get stuck because their business is an undocumented mess. Before I even read the thing and tried, they are already trying to give me the answer. When I ask 'is this documented and if so, how would it be discovered easily' their first reaction is 'no' followed by a lengthy explanation which should be in the wiki and easy for newcomers to find.
And it shows when I forget a few days later because my brain never put in the effort to get to the answer and my memory is that of a fruit fly's.
(This is a big problem if you've ever had a problem with Android.)
1. Paying attention to error messages
2. Reading documentation
3. Looking up stuff I don't fully understand(including googling error messages)
That's it.
Some people don't even read error messages at all. I understand non technical people doing that, but I've seen far too many engineers doing it. If anything doesn't go exactly as expected, they freeze. I have no idea how a person gets so far in their careers without reading error messages. Actually, I do, those people ask others to figure out stuff for them. That's way prevalent in enterprise settings. Sure, collaboration is good, but I've seen a lot of instances where there's a massive imbalance – you'll have 10 people pinging a single person to 'unblock' them. They could have spent a couple of minutes trying to figure out yourself.
I'll move mountains to help someone that comes to me after having done some basic homework to try to fix (or at least triage) an issue. It very rare though.
It's also amazing how many people will just go ahead without having read a single line of documentation of the thing they are working on. I've even had a developer dive in a Golang codebase without having _ever_ worked on the language. That would have been fine – that's how I learn new languages, just get accustomed, before doing some more formal training and exercises – except that he continued to not read the language documentation before asking a bunch of questions. Needless to say, the questions weren't good.
And number 3... just rubber ducky everything. If you can't explain it, you don't get it. Go read up on the topic. Sometimes I'll find out that I don't fully understand something as I'm writing an email to others.
This. I actually am OK with people not figuring out even basic stuff. But please, at least try to give the impression that you've put some effort in, instead of just trying to have me do your homework while you browse facebook or whatever.
These are rare, but they also tend to be the really effective ones. We have a couple of teams who understand the stack, read documentation and read error messages. We generally don't hear of them for months and months, because they are too busy being productive.
But when we hear of them, it's usually time to push boundaries of the infrastructure and the processes. They tried everything and nothing worked and now it's time to make it work.
Can't really blame people for that too much, most language documentation is utterly unreadable unless you already know exactly what you're doing. And even if you do get it, it's in one eye and out the other. Most people just don't learn very well from reading technical information you don't need to use right away. You might be a happy exception and got to build up your notoriety that way
Language documentation is for looking up nitty-gritty details. You go there if you already know what you're looking for. It works for some languages and for some people, but reading it from top to bottom is usually a horrible way to learn a programming language.
"DANGER! Confirming this action may result in 8 figures worth of scrap!!!"
Even if you are super careful and make sure your error messages are terse in all cases, you will still succumb to things like muscle memory among your users. I've caught myself mindlessly dismissing these while testing. How can I expect my users to be better than the person who developed the UI? That is unreasonable.It got to a point where we started removing these alerts/confirmations because it was training people to do the wrong thing in a few places. If you have part of a UI where all actions are immediate and final, the game theory changes. The moment a user enters into one of these spaces, they are much more cautious.
If the user thinks the UI will save them, they may eventually tire of these protections and forget why they are there in the first place. I feel like this is very similar to the problem of driver assistance and partial self-driving capabilities today.
In theory, all errors should: explain the input, explain the problem and explain how to solve the problem (actions). And that should help and reduce number of support calls. However, error messages and actions how to solve the error are read by maybe 1% of users.
The only way to improve your UI is to prevent errors and use standards / familiar design.
Most systems I was involved in designing have some kind of error tracking system, so we can know exactly how often each error occurs.
An error that never happened needs (usually) no attention.
An error that 28% of installations have seen needs a lot of attention. The error text should be translated into local languages, wiki pages should be written about how to resolve it, efforts should be made to auto-resolve the error. The error message should include helpful info, etc.
Eg. "SSH server can't start. Config file unreadable".
Could be split into:
SSH server can't start. Config file error on line 7. 'AllowPasswordLoogin' is an invalid setting. Did you mean 'AllowPasswordLogin'? If you want to make this change, 'sudo nano /etc/sshserver.conf' will let you change this config.
If the error bubbles up to the user, then either the information is over their head, in which case there's no difference to a non-detailed error message, or the user/support person can actually act on it.
The most infuriating error I see is "file not found"... WHICH FILE?!
Of course if the error is found in the higher level due to some consistency check in the business logic, then yeah try to guide the user. But for internal stuff, try to help the person who needs to fix it or find a workaround. It might be you.
Filenames might contain user data, which must not be logged outside of a database with proper access control, schema annotations, and acccess auditing.
We can only display an opaque object key, so authorized devs can look up the filename using secure tools.
For the majority of errors in most applications one can provide some helpful information. But yeah, one need to be a bit careful if one has PII in the mix.
> If the error bubbles up to the user,
...then you have an information disclosure vulnerability! There's a really good reason why we don't bubble up deep exceptions to end users: Attackers can use that info to gain information about your back end that they can use to find worse vulnerabilities.
Put all the detail you want in your logs. Keep the end users out of it. They shouldn't be able to tell what line broke things.
The first one is from PayPal. Whenever I try to add a US bank account to my PayPal account, it says something like "You cannot add this bank account at this time, period"
After more than a year, it turned out that there was no way to add such an account for a foreigner, despite my friends [from the same country] being able to do it easily a couple of months before.
The second one is, poor me again, trying to edit a Facebook page URL I created for a side project, that should read FB.com/[SIDE_PROJECT], where FB keeps rejecting my request with a generic/ unexplained/unhelpful error message despite the page URL name was available.
About a year later, I got it working by, SIMPLY, having my phone number verified! How bad!!
1. Information that can help a technically engaged person debug a problem.
2. Information that can help a user of the system understand what they have to do the overcome the problem.
Since most error messages are created by people responsible for debugging the system they tend to be of the 1st class. There has to be a way to provide different information based on who is getting the error.
Yes, this concept exists. The error message that is shown to the user (number 2) is what's discussed in the article. The error message that an engineer or someone else debugging the system should get (number 1) is the full stack trace and data dump that should be sent to the application log at the same time that the user is shown the error dialog.
Users can fix the problem by following the instructions in the error dialog and engineers or technical people can come back later and look at the more detailed stack trace to determine the best course of action.
This is already solved. Provide one error to the user and another to your logging system. In the user error provide a mechanism to point you to the logged error (even a simple timestamp helps).
There's one thing I wasn't sure about in this article though. Did they talk to actual users regarding these empowered error messages or even asked them what they want to see out of common error messages they run into? It seems rather difficult to empower error messages without first understanding the scenarios that got them into the error state to begin with. Next would be understanding if these error messages are helpful to the users and asking them how they go about resolving these types of issues. All of that is hinted at in the "what makes a good error message".
First of all, unless I'm writing an engineering tool, my users aren't geeks, and don't especially care why the error is happening (geeks always need to know why). They just need to know that what was expected, did not happen. If there is a remedy, and it can be simply stated, then I can add that, but it needs to be short and simple. Longer stuff needs to go into some kind of secondary screen (which probably won't be read).
Also, I take the "shopkeeper" approach. The customer is always right, and it's never the customer's fault. I avoid any hints of blaming the user (even if it is their fault), and try to be polite and helpful[0].
Of course, the best way to deal with errors, is to avoid them. I try to design good affordances.
The rules are different for SDKs, though. In that case, I tend to send a great deal of information back. I take advantage of Swift's enums, and the ability to associate data. It can allow me to nest error reports.
[0] https://littlegreenviper.com/miscellany/the-road-most-travel...
Sometimes the data (and error-messages) are flowing up and down through many different modules and APIs and job-queues and whatnot, that when an error pops up it saves a lot of developer-time when you can just text-search on the code repo(s) and see exactly the line that generated it in the first place.
If Wix can save the data locally, why not just copy the GMail error interface and let the user decide when to connect to internet?
- Can an end-user solve the problem themselves? If so, tell them how, if not, display a generic error message telling them to ask for support (with an error identifier they can tell the support)
- Developers and end-users need different information: developers need as much information as possible, like file names, contents of important variables and especially where the error happened in the source code with a backtrace, sometimes even two backtraces: the backtrace for the cause of the error, too; and end-users only need to be told what they can do, but this needs to be worded clearly and carefully. This means that error messages need to be written twice.
- Is the problem serious? If so, report, crash and restart, if not, just report and abort the affected operation when neccessary.
- The problem should be logged. Sometimes it can be sent to developers automatically.
This is why I love exceptions, I had an issue with a C# game, but with a stack trace I could figure out myself that the issue is happening when the app initialize and fails to open a file.
I think twe should always give the users a detailed log and stack traces, also docker should fucking have some way to catch the issue when there is not enough space and report the error properly.
"500. It's an error."
Thanks, google. I tried to start a chat (I'm a Workspace customer) and could not continue because all the language choices were disabled (even English).
Meaning, the "way out" is to point users to customer care, but this still does not help if customer care is shit. And we know it often is.
Customer care should be an email address (and/or phone number) in the footer. Not a contact form. Self-help/FAQ is fine, but no replacement for direct contact. Nor is a shitty AI bot.
And when contacting support directly, answers should not be scripted non-sense completely ignoring the actual issue at hand.
I don't care if it doesn't scale. Make it scale. Your problem.
1. Always have an error specific URL to point at. Changing a document stored outside the system is often significantly easier than redeploying a system (order of magnitude seconds or minutes vs. hours or days in the worst case). There are many benefits to this approach. It's available when your system is not. It's possible to look at metrics and collect NPS scores on the information. It's easy to add pictures, steps, links etc.
2. Try to add an operation specific correlation ID. This allows the user to talk about a specific instance of an error easily when dealing with support and developers to look for specific log info. This is also useful if you provide a 'get support' link on errors that require manual intervention.
3. Add an error specific identifier to help developers map error strings back to source code. Often with error messages that are string interpolated the unique values tend to obscure the non-unique parts of the message. Also messages that are fairly similar can make it more difficult for a developer to find the specific cause.
These are not alternatives, but additions to TFA's suggestions.
1. For the user.
You can't do that (maybe explain why). Don't do that.
2. Error that's actually there for the support or engineering team for a customer to convey to support, probably with a handy copy to clipboard link (that the user has at best a 50/50 chance of using no matter how much prodding).
That's it.
Humans generally lock up hard when they see an error in my experience. No amount of information or hand holding will help most of them figure it out. It's better to try to solve it in software.
If the software can't fix the issue internally then they get an error message and 2 things happen:
1. The user is going to try something else and solve it themself (awesome) regardless of the error because they're smart and capable people and could probably solve it no matter what you told them.
2. Their brain locks up, they do the same thing 20 times and get the same result and complain to support with some form of "doesn't work". Doesn't matter what error you give them, they won't even try to tell you what the error was / doesn't register in their brain unless it had a cute cat on it or something (that actually works... so forget this "tone" stuff).
I like the article, but I am skeptical about a UX team who doesn't answer support tickets ... just magically knows what the user is thinking / will work. I get lots of advice on error messages, I change them when they ask, but when it's from folks inside the company who know the product it often isn't helpful.
Heck even users give bad advice about errors. I've had them tell me "Well it should have said X" where X is exactly word for word what it said (they forgot...).
Granted I still try to help the user along, but I'm skeptical that software with any large user base can have "good" error messages.
Error handling has been left to engineers, and when left to they own devices engineers will almost always make the wrong choice from a user point of view.
Engineering need to think of error messages this way: the error message is there to help people (which might be fellow engineers, support, and/or and your consultants) identify the error quickly so that they can manage the user's expectations, fix the error, and/or both.
Unfortunately, many engineering paradigms make this an impossible task.
Layering and encapsulation means that you have little idea what's happening downstream or how the downstream stuff actually works, but the lower-level you are the less likely the error will mean anything to the end-user.
Then, it's a question of who's responsible for handling the error? If you're on the backend, where does it go? Does the user care that the backend microservice can't connect to the database? Heck, the UI probably has no idea what's happening back there.
However, for accurate troubleshooting detail is needed.
For many orgs, leaving transaction IDs in your log files is the primary way that you figure out errors, especially in big distributed systems. That doesn't really help end-users, and requires developer discipline, something many engineering teams find challenging.
Ideally error objects would aggregate error codes up the stack, so that if an error occurs you can at least present technical people with the errors that were thrown..and they can search through the source code trying to find that unique error code. But designing that is difficult; conceptually you don't want a list of 500 error codes being thrown upwards, one from each function in the call chain. But sometimes you do.
Anyway, error handling design really should be part of the initial architecture, but it usually isn't because architecture guys don't really understand support.
Since the fault code paths (hopefully) are very rarely executed, the error messages are easy to overlook, and tend to rapidly become stale. This is to an extent always a problem with error messages, but it's an ever bigger problem when you have half a dozen error messages depending on various parameters, since they create more and even more rare code paths for staleness to hide in.
Could not connect to server? Check if WiFi is on. Check if Dns is working. Check if ping to router is working. Check if ping to google is working. Link to wifi settings.
Whatever you do. Just don’t do this the reverse way, like my smart ass Samsung tv does! It determines if internet is working by pinging a Samsung server, before it even allows other apps to use their internet. You can probably figure out what will happen when Samsung servers are down.
My toaster is a complex bit of engineering - it has thousands of parts which all work together to take power from the wall to make toast.
Yet it has no errors. It just does the job I ask it to do.
A computer on the other hand seems to have a lot of ways to fail, and does so nearly every day. I suspect everyone reading this comment has seen at least one error today. Can't we engineers make the software better so that these errors can't/don't happen?
On a more serious note, error messages is something I always try to keep in mind on in code reviews. Most error messages the code I review deals with are only ever seen in production logs, so I try to think what I'd do with that message (and accompanying details) if I saw it in production.
I'd like to learn how to make more meaningful error messages in compilers, particularly "low code" compilers that slice code transformations thinly and thus have a hard time explaining which lines of code are interacting to create this situation that happens at phase 39.
<looks at TypeScript>This actually means "if you like wasting your time and want to speak to incompetent fools who will pass you to an endless stream of their 'colleagues' then dial this number."
Do they mean “Unable to connect to your account”? Because otherwise it’s not clear to me what this is about. Connect my account to what? This doesn’t read like a user-level concept.
'due to a technical issue on our end'
but isn't that also generic and obvious which they were trying to avoid too.
A UX person telling us not to do what the previous UX person thought was cute.
Thank you sooo much! Ask PM for a pat on the back.
“Deployment failed because: deployment succeeded”
That is all.
This is the opposite of what I want. Stop condescending and just tell me what actually went wrong.
If it's proprietary locked down user-hostile junk, then yeah, all I want in the error message is a statement of a refund on my payment, and a link to a competitor website.
Was it a timeout? Maybe an HTTP 401 Was it a DNS failure Was there a TCP reset immediately?
Each one has a miriad of troubleshooting steps associated with it. Some could be local to the host, some could be network/firewall some could be from the remote host or behind that.
Now, "your credentials have been denied" seems pretty clear and does not use jargon in my opinion, but telling the user "the ajax request failed, returning a 403 http error code" seems unhelpful and doesn't tell them what happened.
I know it is a made up example, but it does show the problem with "dumbing down" the error messages. Details matter.
It's impossible to figure out what goes wrong. Plenty of people have the same problem, but Google only has this forum where superusers assume everybody else is either lying or an idiot. Meanwhile, they take such error messages at face value, despite many people saying they have wifi.
All that to say that I'd rather have an overly technical error that actually tells me what's wrong, instead of a friendly error message that's straight up wrong.
I need the technical jargon to do support's — and the company whose product I'm using's — job for them.
Is it not helpful to laypeople? Perhaps not, but it is what the technical friend they're going to drag into the problem needs.
Wix is mostly a platform for non-techie DIY website builders. I can't imagine they'd know what to do with a highly technical error.