UI/UX Atlas
Content & UX Writing Intermediate

Error & Validation Messaging

Craft error and validation messages that help users recover fast — covering timing, specificity, WCAG 2.2 accessibility, and the language patterns that actually work.

9 min read

The full lesson

Errors are the moments of highest friction in any product. When something goes wrong, the error message is the entire user experience at that point. Get it right and users recover in seconds. Get it wrong and they abandon the task, blame themselves, or call support.

Error and validation messaging lives at the crossroads of writing, interaction design, and accessibility.

Why Most Error Messages Fail

The most common error pattern is still the generic catch-all: “Invalid input,” “An error occurred,” or “Please fix the errors above.” These messages share three problems: they use system language, they give the user nothing to act on, and they dump the cognitive load onto the person who already hit a dead end.

The root cause is organizational. Errors are often written by engineers as afterthoughts, copy-pasted from API responses, or left as framework defaults. A developer’s instinct is to surface the technical reason (“404 Not Found”, “422 Unprocessable Entity”). A UX writer’s job is to translate that into a human instruction.

Modern products treat every error state as a designed touchpoint with a content spec — not a fallback string.

The Anatomy of a Good Error Message

Every effective error message answers three questions:

  1. What happened? — State the problem in plain language, from the user’s perspective.
  2. Why did it happen? — Give just enough context so users understand what went wrong.
  3. What should they do next? — Provide a specific, actionable recovery step.

You don’t always need all three in full. Short inline field errors can be brief as long as they answer question 3. Full-page error states need all three, plus an escape hatch (a clear next step so users aren’t left stuck).

The minimal formula

For inline validation errors, a reliable formula is:

[What the field needs] + [why the current input doesn’t satisfy it] (when non-obvious) + [how to fix it]

WeakStrong
Invalid emailEnter a valid email address (e.g., [email protected])
Password is too shortPassword must be at least 8 characters — add more characters to continue
Required fieldEnter your date of birth to continue
Something went wrongWe couldn’t save your changes. Check your internet connection and try again

The strong versions are specific enough that the user can act without re-reading the field label.

Timing: When to Validate

Validation timing has a bigger impact on perceived quality than the wording itself. Show errors at the wrong moment and even a perfectly written message feels accusatory.

The outdated pattern: validate on submit

Validating only on form submission was the default for most of the 2000s and early 2010s. Users filled out an entire form, hit Submit, and got a list of every problem at once. This pattern causes:

  • Frustration cascade — fixing one error can introduce another
  • Memory load — the user must hold their original intent while scanning an error list
  • Low confidence — users feel ambushed after completing what felt like a finished task

The modern pattern: validate on blur, not on input

The current best practice is to validate each field after the user leaves it — on the blur event, which fires when focus moves away from the field. Do not validate while the user is still typing. Showing “You must enter a valid email” before the user has typed the @ character is aggressive, generates false positives, and erodes trust.

Rules of thumb:

  • Trigger validation on blur for most fields
  • For password-strength indicators, live feedback on input is acceptable — use progressive disclosure rather than error language (“Strong” / “Getting there” / “Too short” feels different from a red “Invalid password”)
  • Re-validate on input after an error is shown, so the error clears as soon as the user fixes it — this gives immediate positive feedback
  • Always run a full validation pass on submit as a safety net

Do

Validate on blur so users complete their thought before seeing feedback. Clear the error immediately when the field becomes valid again. For password fields, show strength progress (not just failure) during typing.

Don't

Validate on every keystroke — this flags incomplete entries as errors. Only validate on submit — users get a jarring list of problems after investing effort. Use passive-voice or system-language errors (“input was not recognized”).

Accessibility Requirements (WCAG 2.2)

Error messaging is a first-class accessibility concern. WCAG 2.2 (the Web Content Accessibility Guidelines, the international standard for accessible web content) defines specific success criteria that go beyond “make the text red”:

3.3.1 Error Identification (Level A) — If a field contains an error, identify the item in text and describe the error in text. Color alone is not sufficient.

3.3.3 Error Suggestion (Level AA) — If an input error is detected and suggestions for correction are known, provide the suggestion.

3.3.4 Error Prevention (Level AA) — For legal, financial, or data-deletion operations, give users a chance to review, correct, and confirm before submitting.

2.5.3 Label in Name (Level A) — Visible text labels must be reflected in the accessible name. If the visible label says “Email address,” the aria-label or accessible name must contain those words.

Implementation patterns

The correct way to connect an inline error to its field is aria-describedby pointing to the error element’s id. The error container must be present in the DOM — use aria-live="polite" or role="alert" for dynamically injected errors so screen readers announce the message without requiring the user to navigate back to the field.

<label for="email">Email address</label>
<input
  id="email"
  type="email"
  aria-describedby="email-error"
  aria-invalid="true"
/>
<p id="email-error" role="alert">
  Enter a valid email address (e.g., [email protected])
</p>

Setting aria-invalid="true" on the input tells assistive technology the field is in an error state before the user reads the description. This gives them the context to expect corrective instructions.

Tone and Voice in Error Messages

Tone is the second most common failure mode after vague content. Two pitfalls dominate:

Blaming the user — “You entered an invalid date.” The user didn’t do anything wrong by trying; the form rejected their input. Prefer neutral or system-owned framing: “This date format isn’t recognized — use DD/MM/YYYY.”

Being overly apologetic — “We’re so sorry, something went terribly wrong on our end!” Excessive apology adds words without adding information and can undermine confidence in the product.

The right register is calm, direct, and specific — like a knowledgeable colleague explaining what to try next. It is not a customer service script, not a legal disclaimer, and not a scolding.

Dos and don’ts for tone

PatternWeak exampleStrong example
BlameYou entered the wrong passwordThat password doesn’t match — try again or reset your password
VaguenessSomething went wrongWe couldn’t complete your purchase. Your card wasn’t charged — try a different payment method
Excess apologyWe’re so sorry for the inconvenience this has caused youWe couldn’t load your file. Make sure it’s a PDF under 10 MB
JargonHTTP 403: ForbiddenYou don’t have permission to view this page — contact your admin to request access
ScoldingYou must fill in all required fieldsFill in your name and email to continue

When to use “we” vs. “you”

Reserve “we” for system-caused failures: “We couldn’t connect to the server.” Use “you” (or an imperative with no subject) for actions the system needs from the user: “Enter your date of birth” rather than “You need to enter your date of birth.”

Network and System Errors vs. Validation Errors

These two categories of error need different content strategies.

Validation errors are predictable and synchronous. The user gave input the system can’t process. The system knows exactly what’s wrong. Messages can be specific, immediate, and field-level.

System/network errors are asynchronous, and the cause is often partly unknown from the user’s side. Messages must:

  • Acknowledge that something went wrong without blaming the user
  • Give the user a concrete next step even when the root cause is unclear
  • Preserve their work or state where possible (“Your draft was saved before the error”)
  • Provide an escalation path (reload, retry, contact support) rather than a dead end

A common mistake is writing network error messages that assume too much: “Your internet connection is down.” The product often can’t know if the problem is on the client side, the server, a CDN, or something else entirely. Prefer: “We couldn’t reach our servers. Check your connection and try again, or reload the page.”

Writing for Form-Level vs. Field-Level Errors

Most forms need two tiers of error messaging working together.

Field-level (inline) errors appear next to the specific field, triggered on blur. Keep them short (one sentence), specific to that field’s requirement, and clear them as soon as the field is valid.

Form-level (summary) errors appear at the top of the form (or a modal header) when the user submits and problems still exist. They serve two purposes: moving screen reader focus to the top of the error zone via role="alert", and orienting sighted users who need to scroll back up.

A good form-level summary does not repeat every individual field error. Instead it:

  1. States how many fields need attention: “Two fields need your attention before you can continue”
  2. Links to each field by anchor: “Email address · Password”

The individual field-level errors carry the specific guidance. The summary just routes users there.

Preventing Errors Before They Happen

The best error message is the one you never have to write. Content design can reduce error frequency through:

Input constraints — Show format hints and inline examples in labels or helper text: “Date of birth (DD/MM/YYYY).” These should be visible at all times, not just as placeholder text, which disappears when the user clicks into the field.

Smart defaults — Pre-fill fields where data is known (phone country code, country based on IP). Let users override, but don’t start from blank.

Forgiving formats — Accept “07700 900000” and “+44 7700 900000” as equivalent. Strip spaces and hyphens before validation. Meet the user where they are.

Progressive disclosure — For complex multi-step forms, surface requirements only when they become relevant. Don’t show a wall of instructions before the user begins.

This maps to WCAG 2.2 criterion 3.3.7 (Redundant Entry) — avoid asking users to re-enter information the system already has, which is also a significant source of unnecessary validation errors.

Checklist Before Shipping

Before any form or error state ships, run through this checklist:

  • Every error identifies the field by name (not “This field” or “This”)
  • Every error tells the user what to do, not just what went wrong
  • No error relies on color alone to signal a problem
  • All inline errors are connected with aria-describedby and aria-invalid
  • Dynamic errors injected after load use role="alert" or aria-live
  • Validation fires on blur, not on every keystroke
  • A form-level summary is present for multi-field forms
  • System error messages include a retry or escalation path
  • No jargon, no blame, no excessive apology
  • Messages have been reviewed by both a UX writer and tested with real users