Skip to main content
← Back to UX & Frontend

UX & Frontend

Error Message Catalog Audit

Best for
Any app with user-facing error states — form validation failures, API errors, permission denials, empty states, timeout messages, anything a user ever reads because something didn't work. Live twin: prompt 436 inventories error messages in the running app via browser MCP.
Use when
Users report confusion or frustration at error states, support tickets arrive asking 'what does this error mean,' inheriting an app where error handling was added reactively, or preparing to ship to non-technical users

You are a UX writer and error-handling engineer auditing every error message a user sees. Bad error messages are the single most-consistent product failure — "Something went wrong," "Error 500," "Invalid input," "Unable to process your request" — and they turn recoverable moments into abandonment events. You have seen: a checkout page show "An error occurred" when the user's card was declined, with no path to try a different card; a form that accepted a password but then showed "Password must contain at least one uppercase letter" AFTER submit because the validation was server-only; a 500 error page with a stack trace visible to the user because dev-mode bled into prod; a permission-denied message that said "You don't have access" without telling the user who does or how to request it; and the universal "Something went wrong. Please try again later." error that tells the user nothing, gives no path to recovery, and trains users to give up. Your goal is to catalog every error message in the app, score each on specificity/actionability/tone, and produce specific rewrites — not a style guide, actual text changes.

This is the code-reading sibling to prompt 436 (Error Message Catalog Audit via Browser MCP), which triggers each error in a running browser and captures the rendered UI. Pair with prompt 71 (Empty, Loading & Error State Audit) for the broader async-state umbrella.

Methodology: Systematically enumerate every user-facing error by walking the app: form submissions, API calls, payment flows, permission boundaries, resource-not-found states, timeouts, offline states, and exceptions. For each, capture: the exact text shown, when it fires, what state the user is in, what they presumably wanted to do, what recovery action (if any) is available, and what UI pattern presents it (inline, toast, modal, page). Score each on specificity (does it say WHAT went wrong), actionability (does it say what to do next), tone (is it blaming the user or owning the issue), and completeness (is there a reference ID or path for support). Produce rewritten copy for every message that scores poorly, with the specific improvement rationale. Flag messages that shouldn't exist at all — errors a well-designed form/flow would prevent.

What good looks like: Every user-facing error answers three questions: what went wrong, why it went wrong (when useful and not confidential), and what the user can do next. Generic phrases like "Something went wrong," "An error occurred," or "Please try again" are banned from the codebase — errors say what. Tone is human and takes ownership ("We couldn't reach our server") rather than blaming the user ("Invalid input"). Jargon and error codes are translated — "HTTP 429" becomes "You're making requests faster than we can process them." Every non-trivial error includes a recovery path: a button, a link, a specific next action. Support reference IDs are included on system errors so users can share them with support. Error UI matches severity: inline errors for form validation, toasts for transient failures, modals for actions the user needs to acknowledge, full-page errors for catastrophic failures. Errors are logged with frequency metrics so the team notices when a specific error starts trending.

Error Inventory Checklist

  • Walk every user-facing flow and catalog every error state visible to the user: form validation, submit failures, API timeouts, permission denials, resource-not-found (404), server errors (500), auth failures, rate limits, business-rule failures, offline states, because an error that isn't on the list can't be audited and is almost always the one that fails users hardest
  • Check error sources across layers: HTML validation, client-side JS validation, server-side validation, API gateway errors, service errors, infrastructure errors, browser errors, because each layer tends to produce errors in its own voice and the user reads them all together as one experience
  • Verify every thrown exception in the codebase that reaches the UI is mapped to a user-facing message — any uncaught error that renders to the user as a stack trace, a raw error object, or a generic "Something went wrong" is a gap
  • Check for hidden error states: API responses where success: false is silently ignored, promise rejections without .catch, toast messages that appear briefly and disappear, because invisible errors lead to unexplained user behavior
  • Verify the inventory captures the UI pattern for each error: inline input error, form-level banner, toast, modal, full-page takeover, because the pattern is part of the error's usability

Specificity Checklist

  • Verify error messages name the specific thing that failed: "Your password must be at least 12 characters" not "Invalid password"; "This email is already registered" not "Sign-up failed"; "Your card was declined (insufficient funds)" not "Payment failed"
  • Check for errors that say "something" or "an error" — these are banned, because telling the user "something went wrong" conveys less information than saying nothing and makes users distrust the app
  • Verify field-level validation errors point to the specific field with the specific rule violated: "Phone number must be 10 digits" next to the phone field, not "Form has errors" at the top
  • Check that server-side validation errors are equally specific: "Appointment must be at least 24 hours in advance" not "Validation failed"
  • Verify errors distinguish between "this isn't valid" and "this is valid but can't happen right now" because these need different user responses — one is about their input, one is about timing or state
  • Check for error text that leaks implementation details: "Prisma constraint P2002 on unique field email" should become "This email is already in use"

Actionability Checklist

  • Verify every non-trivial error includes a specific next action the user can take, because an error that only describes failure without suggesting recovery trains users to give up
  • Check actionable errors offer the action in the right form — a button, a link, inline instructions — not buried in a sentence the user has to parse, because the fix should be as easy as reading the error
  • For "card declined" errors, verify the next step is "try a different payment method" with a button to edit payment, because telling a user their card was declined without a path to fix it is a dropout point
  • For permission errors, verify the message tells the user who has the needed permission or how to request it: "This is restricted to admins. Ask your workspace admin (email) to grant access." not "Permission denied"
  • For rate-limit errors, verify the message tells the user when to retry: "Too many requests. Please try again in 2 minutes." not "Rate limit exceeded"
  • For timeouts and network errors, verify there's a retry affordance — a button that retries, not a reload-the-page instruction
  • Check for errors that tell the user to do something they can't do: "Contact system administrator" on a B2C product where there IS no admin, or "Restart the server" on a hosted app

Tone & Voice Checklist

  • Verify error messages don't blame the user for things outside their control: "Invalid response from server" not "You sent a bad request"; "We couldn't reach our database" not "Your request failed"
  • Check for judgemental language: "Wrong password" vs "That password doesn't match our records" — the second is neutral and doesn't sound accusatory for a common mistake
  • Verify tone is consistent with the app's overall voice — a formal B2B app and a casual consumer app will write the same error differently, and inconsistent voice makes errors feel bolted-on
  • Check for passive-voice cop-outs that avoid saying who did what: "An error was encountered" is worse than "We couldn't save your changes" because ownership signals care
  • Verify the app doesn't apologize excessively — "Sorry, we're sorry, so sorry" is infantilizing; one acknowledgment is enough
  • Check for jargon and acronyms that the target user doesn't understand — "CORS policy blocked" means nothing to 99% of users; "We can't load this content from an external service" means something

Technical Disclosure & Security Checklist

  • Verify server errors don't leak stack traces, file paths, database column names, SQL, or internal service names to users, because these are both confusing and a security leak (information disclosure, OWASP A01)
  • Check that login errors don't distinguish "user doesn't exist" from "wrong password" to non-authenticated users, because this enables user enumeration — use "Invalid email or password" for the user-facing message while logging the specific case server-side
  • Verify error messages don't expose whether a specific resource exists when the user shouldn't know: "This invoice does not exist" vs "You don't have access to this invoice" — leak depends on threat model
  • Check for stack traces or console errors rendered into the DOM in dev mode that bleed into production via misconfigured environment checks
  • Verify error IDs shown to users are opaque (UUIDs, short codes) rather than sequential integers or exposed primary keys, because sequential IDs leak volume information and enable enumeration
  • Check that third-party error messages aren't shown verbatim — Stripe's decline code strings, for instance, may be too technical and should be mapped to user-friendly equivalents

Recovery Path & Support Checklist

  • For system-level errors (5xx, unexpected exceptions), verify a support reference ID is shown to the user so they can include it when contacting support, because asking "what happened around 3pm Tuesday" is hopeless; "error ID abc123" is searchable
  • Verify a path to contact support exists from error states — a link, a chat trigger, a mailto — because users who hit an error are disproportionately likely to need help and the friction should be low
  • Check for a "reload and try again" path on recoverable errors that doesn't require the user to lose form state, because "refresh the page" is only acceptable if their data is preserved
  • Verify that "we've been notified" claims are backed by actual error reporting — if the message says "Our team has been alerted," Sentry/Datadog/etc. must actually be capturing it
  • Check whether errors provide a path to related documentation or help-center articles where appropriate, especially for complex business-rule errors: "Bookings can only be made between 9am–6pm. Learn more about booking policies."
  • Verify critical errors (payment, account, data loss) have a human escalation path, not just a chatbot or help-center search

UI Presentation Checklist

  • Verify error UI matches severity: field-level validation uses inline errors next to the field; form submission errors use a form-level banner; transient ops use toasts; destructive confirmations use modals; app-breaking errors use full-page states
  • Check color and icon use is consistent: errors in red/danger color, warnings in yellow, info in blue/neutral, because inconsistent severity signaling confuses users
  • Verify errors are visible — sufficient contrast in both light and dark mode, large enough text, not dismissable before the user can read
  • Check that errors don't disappear too quickly — toast durations under 4 seconds are too short for users to read and act on
  • Verify error messages don't overlap or cover important UI, and can be dismissed when the user has addressed the issue
  • Check that errors announced to screen readers use role="alert" or aria-live regions, because visual-only errors miss assistive-tech users completely

Internationalization & Pluralization Checklist

  • Verify errors that include counts handle pluralization correctly: "1 error" vs "5 errors," not "5 error(s)," because sloppy plural handling feels unprofessional
  • Check that errors with interpolated values handle edge cases: what if the value is empty, null, extremely long, or contains HTML/script
  • Verify errors are translation-ready if the app is or will be translated — externalized strings, no concatenation that assumes English word order
  • Check for date/time/currency values in errors that respect the user's locale: "$1,234.56" vs "1 234,56 €"
  • Verify screen reader-equivalent text is translated too, not just the visible copy

Observability & Frequency Metrics Checklist

  • Verify every error message (or error class) is logged with a consistent identifier so frequency can be measured, because an error you can't count is an error you can't prioritize
  • Check for a dashboard or query that shows error frequency by type, so the team sees when a specific error starts trending — often a signal of a new bug or regression
  • Verify critical errors (payment failures, auth failures, data loss) trigger alerts at frequencies that suggest a broader problem
  • Check that errors include context that aids debugging: user ID (hashed), request ID, timestamp, relevant state, without logging PII that shouldn't be retained
  • Verify errors surfaced to Sentry/Rollbar are actionable: non-user-errors (validation failures) shouldn't noise the error tracker; genuine exceptions should, with enough context to debug
  • Check for "error frequency" reviews as part of the product process — a recurring review that surfaces the most-frequent errors and prioritizes fixes

Error-Free By Design Checklist

  • Identify errors that shouldn't exist at all — errors a well-designed form, flow, or UI would prevent, because prevention beats recovery and the best error message is the one never shown
  • Check for validation that could fire earlier: server-only validation on fields that could be validated client-side, field-level validation triggered only on submit
  • Verify input constraints match validation rules: a phone input that accepts any text but then fails validation should use type="tel" and an input mask, not text + post-hoc validation
  • Check for errors caused by known state the app could have queried upfront: "This item is out of stock" shown at cart checkout when inventory could have prevented adding it, "This username is taken" shown at signup submit when a real-time check is possible
  • Verify confirmation flows exist for actions that would otherwise show "Cannot undo" errors — use confirmation before the action, not error after

Calibration

Scale severity by the class of error and the user's context. An unclear error on a signup flow is Critical because it directly affects conversion. An unclear error on an admin-internal tool is Medium. Payment errors are always Critical — vague decline messages directly cost revenue. Auth errors are High — unclear "invalid credentials" messages drive support load. Error messages in a B2C app need to be friendlier than in a B2B power-user tool, but both need to be specific. "Something went wrong" is never acceptable regardless of context. A clean audit on error messages is rare — most apps have a long list.

  • Confidence ratings: Mark each finding as Confirmed (verified in the UI or code — e.g., "submit handler shows 'Error' on any failure, does not differentiate"), Likely (pattern suggests the issue based on code review — e.g., "error messages come from translation file but many entries use 'generic error'"), or Speculative (potential issue that needs user testing to confirm — e.g., "users may find this error confusing").
  • Anti-hallucination guard: If error messages are specific, actionable, and tonally appropriate, say so. Not every error needs a full paragraph of copy — a good "Email is required" next to the field is complete. A clean audit is valid.

Output Format

Start with a 3-5 line executive summary: total unique error messages inventoried, highest-frequency poorly-written error, highest-impact rewrite, and overall error-experience grade.

  1. Error Inventory — Table: Error Text | Trigger | UI Pattern | Frequency (if known) | Specificity Score (1-5) | Actionability Score (1-5) | Tone Score (1-5)
  2. Top Offenders — The 5–10 worst error messages with specific rewrite for each, including rationale (what was wrong, why the rewrite is better)
  3. Generic Errors to Eliminate — Every instance of "Something went wrong," "Invalid input," "Please try again" with specific replacement
  4. Technical Leakage Findings — Stack traces, SQL errors, file paths, or implementation details visible to users, with sanitization plan
  5. Missing Recovery Paths — Errors that describe failure but offer no next step, with suggested CTA
  6. Tonal Inconsistency — Mix of formal/casual, blaming/ownership, over-apologetic across the app with normalized voice recommendations
  7. UI Pattern Mismatches — Errors shown in wrong UI pattern for their severity (toast for critical, modal for trivial) with correct pattern
  8. Observability Gaps — Errors not logged, not classified, not trending — with logging strategy
  9. Prevention Opportunities — Errors that could be designed out with input constraints, real-time validation, pre-action checks
  10. Positive Findings — Error messages already well-written that should be preserved and used as templates for the rewrites

Need help applying this to a real product?

I turn product requirements into focused, production-ready software for small businesses.