Skip to content
Empty States and Error Screens: Designing for the Moments Users Struggle
UI/UX Design8 min read

Empty States and Error Screens: Designing for the Moments Users Struggle

Scult Team
8 min read

The screens a product shows when nothing is there or something went wrong get less design attention than any other screen — and they're precisely the moments a user is most likely to give up.

Design reviews spend most of their time on the screens that show up in a pitch deck — the populated dashboard, the polished product tour, the "happy path" screenshots that make it into marketing pages. The screens that actually determine whether a struggling user recovers or leaves — an empty search results page, a generic 404, a form that just failed to submit, a permission error with no explanation — usually get built last, styled with whatever default the framework provides, and reviewed by nobody. That imbalance is backward, because these are exactly the moments where a user's patience is lowest and a design's actual quality gets tested hardest.

A well-designed happy path makes a product feel good when everything works. A well-designed empty state, error screen, and edge case is what determines whether a product feels trustworthy and well-built when something inevitably doesn't.

Why These Screens Matter More Than Their Frequency Suggests

An error screen or empty state might account for a small percentage of total screen views in a product, but its impact on user perception is disproportionate to that percentage for a specific reason: it appears at moments of friction, when the user is already less patient and more prone to forming a negative judgment about the product's overall quality. A generic "Something went wrong" message with no explanation and no next step, appearing at the exact moment a user was trying to complete something important, does more damage to trust than a dozen smoothly functioning happy-path interactions build up. Trust is asymmetric that way — it's harder to earn than to lose, and error moments are where it's lost fastest.

There's also a compounding effect specific to new users: someone in their first session with a product has no accumulated goodwill yet. An empty state or error they hit in that first session isn't weighed against months of prior good experiences — it's often the thing that decides whether they continue at all.

Empty States: Guiding, Not Just Explaining

An empty state shows up any time there's genuinely nothing to display yet — a new user's dashboard, a search with no results, a filtered view that matches nothing, an inbox with zero messages. The lazy version of an empty state is a blank area with a single line of gray text ("No results found") and nothing else. A well-designed one does more work:

  • States clearly why it's empty, in specific rather than generic terms — "No projects yet" reads differently from a bare blank space, and "No results match your filters" is more useful than "No results found," because it tells the user why, which points them toward the fix.
  • Offers a specific next action, not just an explanation. "No projects yet — create your first one" with a clear button does more for a stuck user than an explanation alone. For a filtered search with no results, "clear filters" or "broaden your search" gives an immediate way forward rather than leaving the user to guess.
  • Distinguishes between different reasons for emptiness, because they call for different messages and different actions. A brand-new user's empty dashboard needs onboarding guidance ("create your first X"). A filtered view with no matches needs a way to adjust or clear the filter. A genuinely empty inbox (all caught up, nothing to do) can even be framed positively rather than as a problem to solve — "You're all caught up" reads very differently from "No items."

Treating every empty state as the same generic "nothing here" pattern misses this distinction, and it's a common reason empty states feel unhelpful even when they're not, strictly speaking, broken.

Error Messages: Specificity Is the Whole Job

A generic error message ("An error occurred," "Something went wrong," "Invalid request") technically informs the user that something failed without giving them any way to respond to it. Compare that to an error message that names what happened and what to do about it: "We couldn't save your changes because your session expired — please log in again" gives a user a concrete path forward. The generic version leaves them retrying the same action, refreshing the page, or giving up, none of which reliably solves anything.

A useful structure for error messages, whether they're inline form validation, a toast notification, or a full error page:

  • What happened, described in plain language a non-technical user can understand — not a raw error code or stack trace surfaced to the end user.
  • Why it happened, if it's genuinely useful and not overly technical — "your file is too large" is more actionable than "upload failed."
  • What to do next — retry, contact support, check a specific field, wait and try again — stated as a concrete action, ideally with a button or link that performs it directly rather than just describing it.

It's worth explicitly separating user-caused errors (a validation failure, a typo, an expired session) from system-caused errors (a server outage, a timeout, a bug). User-caused errors should be specific and correctable in place — tell them exactly what to fix. System-caused errors should be honest about the failure being on the product's side, not the user's, and should avoid language that implies the user did something wrong when they didn't.

The 404 and 500 Pages Deserve Real Design Attention

A 404 (page not found) or 500 (server error) page is one of the few screens in a product that a user can land on completely unprompted — via an old bookmark, a broken link from a search engine, a typo in a URL, or an actual outage. Because the user didn't choose to be there, these pages have a specific job: reorient someone who's lost, quickly, without making them feel like the mistake (if there was one) was theirs.

A functional error page includes:

  • A clear, non-technical statement of what happened ("This page doesn't exist" rather than a bare "404").
  • A way back into the product that doesn't require the user to already know where they meant to go — a link to the homepage, a search bar, or (for a 404 on what was probably a real but moved page) a suggestion of likely intended destinations.
  • Consistent branding and navigation, so the page still feels like part of the product rather than a jarring, unstyled dead end that makes the whole product suddenly feel less trustworthy.
  • For a 500 or system error specifically, an honest acknowledgment that it's a system issue, and — where genuinely true — an indication of what to do (try again shortly, check a status page, contact support) rather than a vague apology with no path forward.

The occasional playful or branded 404 page design (a bit of humor, an on-brand illustration) can work well, but only once the functional requirements above are met — a clever 404 with no way back into the product is a worse experience than a plain, boring one that actually helps the user recover.

Loading and Partial-Failure States Are Edge Cases Too

Between "fully loaded" and "error," there's a range of in-between states that are just as commonly neglected: a screen where most content loaded but one section failed, a slow connection that leaves a page half-rendered, a partial form submission where some fields saved and others didn't. These states are easy to overlook in design because they don't show up in a simple happy-path or error-path flowchart, but they happen constantly in real usage, especially on unreliable mobile connections.

Designing for partial failure specifically means deciding, section by section, what should happen if that one piece fails to load while the rest of the page succeeds — a retry option scoped to just that section, rather than either silently showing nothing or forcing a full-page reload to recover a single broken component.

Permission and Access Errors Need Their Own Tone

A specific category of error worth designing deliberately, separate from generic system failures, is the permission or access error — a user trying to view a document they haven't been granted access to, a feature gated behind a plan they haven't upgraded to, a page that requires a role they don't have. These are easy to handle carelessly with the same generic error treatment as a broken request, but they call for a different tone entirely, because nothing is actually broken — the system is working correctly, just declining a specific action.

A well-handled permission error explains the actual reason plainly ("This document is shared with a different team" or "This feature is included in the Growth plan") rather than a vague "Access denied," and, where appropriate, offers the specific next step that would resolve it — requesting access, upgrading a plan, contacting an admin — rather than leaving the user to guess whether it's a bug, a mistake, or an intentional restriction. Treating a permission boundary as a design moment rather than a dead-end message turns what could read as a rejection into a clear, respectful explanation of why, which matters especially for paid-plan gating, where the tone directly affects whether a user perceives the restriction as fair or frustrating.

Writing Tone Across Error and Empty States

The specific words used in error and empty-state copy carry more weight than their brevity suggests, because they're often the closest thing a product has to a human voice at a moment of frustration. A few tone principles that tend to hold up across products:

  • Avoid blaming language, even implicitly. "You entered an invalid email" reads more accusatory than "That email address doesn't look quite right — mind double-checking it?", even though both convey the same fact.
  • Avoid false cheerfulness at genuinely frustrating moments. An upbeat "Oops! Something silly happened!" tone can land badly when a user has just lost unsaved work or hit a blocking error during something important like a payment. Plain, calm, respectful language ages better than forced personality.
  • Be honest about what the system does and doesn't know. "We're not sure what happened" is a more honest and often more trust-building statement than a fabricated specific-sounding reason that isn't actually accurate.

Building Edge-Case Design Into the Process, Not as an Afterthought

The reason these screens get neglected isn't usually a lack of caring — it's a matter of sequencing. Happy-path screens get designed first because they're the ones stakeholders look at, and edge cases get added later, often by an engineer filling in a default state because no design existed for it. By the time anyone notices, the pattern that's shipped becomes the de facto standard for every subsequent empty state or error in the product, entirely by accident.

A more deliberate approach treats edge cases as a standard checklist item for every new flow, at design time: what does this screen look like with zero items, with one item, with a failed request, with a slow connection, with an expired session. Answering these questions during design — even briefly — costs far less than discovering the gaps after launch, when an engineer has already shipped a bare "undefined" string to production because no design ever specified what should show instead.

At Scult, this checklist is a standard part of the design process on Web Development and Custom Software Development projects — every core flow gets its empty, loading, and error states designed alongside the happy path, not bolted on afterward — because the moments a user struggles are exactly the moments that decide whether they trust the product enough to keep using it.

Want results like this?

Keep reading