Product

What good error messages do that most don't

Editorial · Reveneau · November 11, 2026

What good error messages do that most don't

In the work we do, we spend a fair amount of time reading a product's error messages before we touch its code. It is one of the fastest ways to see how a team thinks about its users under stress. Most of what we find is the same message, repeated in a dozen places, with three words: "Something went wrong."

That message is honest. It is also useless. The person reading it does not know if they should wait, retry, change what they typed, or give up and email support. A good error message answers three questions, in one or two sentences: what happened, why it happened, and what the person can do next. Most shipped error text answers none of them.

What happened: name the exact problem

The first job of an error message is to say, in plain words, what did not work. Not "an error occurred." The actual thing: the file was too large, the code expired, the two passwords did not match.

This sounds obvious and still gets skipped constantly, because a catch-all message is the easiest thing to write. When a developer adds a new check, whether it is a file upload limit, a form validation rule, or a payment failure, the fastest path is to reuse whatever generic error text already exists in the codebase. It works. It also means the person on the other end learns nothing about their specific situation.

The Nielsen Norman Group's error-message guidelines put this first for a reason: the message should be "concise and precise" about the exact problem, not a generic statement standing in for a dozen different failures. A vague message forces the person to guess which of several possible problems they actually hit, and most people guess wrong at least once before they either fix it or leave.

Why it happened: explain the cause in the user's terms

Once someone knows what broke, they need to know why, but "why" here does not mean the internal cause. It means the cause stated in terms the person can act on.

"Error 413: Payload Too Large" is technically accurate and useless to almost everyone who sees it. "This file is 14MB, and the limit is 10MB" describes the same failure in a sentence a person can act on immediately. The difference is not politeness. It is whether the message hands the person the fact they need to fix the problem themselves, instead of a code they have to look up or a phrase they have to guess the meaning of.

This is also where tone matters. Nielsen Norman's guidelines call out language like "invalid" or "incorrect" used on its own, with no explanation, as a pattern to avoid, because it reads as blame rather than as a description of a fixable condition. "Invalid password" tells someone they did something wrong without saying what. "This password needs at least one number" tells them the same fact in a form they can fix in five seconds.

What to do next: give an action, not just a diagnosis

The third piece is the one most error messages skip entirely: a next step. Even a message that correctly states what happened and why often stops there, leaving the person to figure out the fix on their own.

A next step does not have to be complicated. "Try again in a moment" is a next step. "Choose a smaller file, or contact us for large uploads" is a next step. What it needs to avoid is leaving the person at a dead end with no path forward except leaving the page or opening a support ticket for something the interface already knew the answer to.

This is the part that turns an error message from a diagnosis into something genuinely useful, and it is also the part that takes the most judgment to write, because the right next step depends on the specific failure. That is exactly why a shared, generic message cannot cover it: "something went wrong" has no next step to offer, because it does not know what went wrong in the first place.

Why this gets harder as error paths multiply

A product with a handful of screens and a handful of forms can get away with a small, hand-written set of error messages, because someone wrote each one deliberately and there were not many to keep track of.

That stops being true the moment a product starts generating new flows, checks, and validation rules quickly, which is increasingly how software gets built now. Every new form field, every new integration, every new automated check is also a new place where something can fail, and each one needs its own three-part message: what happened, why, and what to do. When new error paths get added faster than anyone is writing text for them, the default answer is the same generic string, copied into one more place, and the gap between how many ways a product can fail and how many of those failures are actually explained to the user keeps growing.

This is not an argument against building and generating code quickly. It is an argument for treating error message quality as a requirement that has to travel with every new path, not an afterthought fixed later. In the work we do, this is one of the concrete checks we write into a project's eval suite: any user-facing error string gets checked against the three-part standard before it ships, the same way a function's output gets checked against its spec. That turns "write a good error message" from a reminder someone might forget into something a build either passes or fails.

A short audit any team can run today

You do not need new tooling to find out how bad this problem already is in a live product. List every distinct error message the product can show a user, across every form, every upload, every integration. Most teams have never done this and are surprised by two things: how many messages there are, and how many of them are the exact same generic string covering completely different failures.

For each one, check it against the three questions: does it say what happened, does it say why, does it say what to do next. A message that fails even one of those three is worth rewriting, and a message that fails all three, which is most of what "something went wrong" produces, is worth rewriting first.

The teams behind that generic string were not being careless. They were moving fast on the part of the product that mattered most at the time, and error text is easy to defer. The fix does not need a redesign. It needs someone to go back through the list, once, and then a standard that keeps the next hundred error paths from falling into the same gap.

A good error message is not a nicer sentence. It is the difference between a user who fixes their own problem and one who gives up or files a ticket for something the product already knew.

Sources

Common questions

What makes an error message good instead of generic?

A good error message states three things in plain language: what happened, why it happened, and what the person can do next. "Something went wrong" states none of these, so the person is stuck guessing whether to wait, retry, change something, or give up.

Why is "something went wrong" such a common error message?

It is the easiest message to write. A generic catch-all covers every failure with one string, so it is often what gets typed in first and never revisited, especially in a code path nobody expected to fail often.

Does a good error message need to explain the technical cause?

No. It needs to explain the cause in terms the person can act on, not the technical one. "The file is larger than 10MB" is useful to a user; "Error 413: Payload Too Large" is not, even though both describe the same failure.

Should error messages ever show a stack trace or error code to a user?

Not to an ordinary user, and not as the primary message. A short reference code can sit alongside a plain-language explanation for support purposes, but the code should never be the only thing the person sees.

How does this connect to a product's growth rate?

A product with a handful of screens can get away with a handful of hand-written error messages. A product that is adding new flows, forms, and integrations quickly is also adding new error paths quickly, and each one inherits the same generic message unless someone writes it deliberately.

Does using AI to generate more of a product's error paths make this worse?

It can, if nobody sets a standard for what an error message must contain before those paths ship. AI can write many new validation checks and failure branches quickly, and each one needs the same three-part message a human would have had to write by hand, or the speed just produces more generic dead ends faster.

What is the fastest way to audit a product's existing error messages?

List every distinct error string the product can show, then check each one against the three-part test: does it say what happened, why, and what to do next. Most audits find that a small number of generic catch-all messages cover a disproportionate share of actual failures, because they are the default when nobody wrote something more specific.

Should an error message ever blame the user?

No. Words like "invalid" or "incorrect" without an explanation put the fault on the person instead of describing the situation. "This password needs at least one number" describes a fixable condition; "Invalid password" does not.

Does fixing error messages require a redesign?

Usually not. Most of the fix is rewriting existing strings and adding a short reason and a next step to each one, not changing how the interface looks. The harder part is making sure every new error path gets the same treatment going forward, which is a process question more than a design question.

Can error message quality be checked automatically before a release?

Yes, in the same way any other requirement can be checked: write a rule that flags any user-facing error string under a certain length, or any string that does not name a cause or an action, and run it as part of the checks before a build ships. That turns "write good error messages" from a reminder into something a build either passes or fails.