aiurx.com

Loading, Error, and Empty States for AI Products

6 min read

AI features spend more of their time in in-between states than most software does. Responses take seconds instead of milliseconds, some tasks run for minutes, the system can decline a request, and usage limits are part of normal operation. These states are where people decide whether a feature feels dependable or broken, so each one deserves deliberate design and its own copy.

Why AI features need more states

Conventional screens mostly get by with three states: loading, loaded, and failed. AI features add several more:

  • Variable waits. The same kind of request can take very different amounts of time depending on its length and on load.
  • Output that arrives gradually. Text can appear piece by piece rather than all at once.
  • Partial success. A multi-step task can finish some steps and fail others.
  • Refusals. The system can work exactly as intended and still decline.
  • Usage limits. Rate limits and quotas are routine, not rare outages.

Treat each as a first-class state with a design, not as an edge case to handle later.

The first second: acknowledge right away

Jakob Nielsen's three response time limits still describe how waiting feels. About 0.1 second feels instantaneous. About 1 second keeps the user's flow of thought uninterrupted, although they notice the delay. About 10 seconds is the limit for keeping their attention on the task. Many AI requests take longer than the first two limits, so the interface has to respond even when the model has not.

  • Show the user's request in place the moment they submit it, so they know it was received.
  • Turn the submit button into a stop control.
  • Where you can, replace a generic spinner with a specific status line. "Reading 12 documents" explains both that work is happening and why it takes time.

Streaming: show the answer as it forms

Streaming, where text appears as it is generated, turns a long silent wait into visible progress. On the web it is often delivered with server-sent events, a one-way channel from server to browser, or with a streamed HTTP response. One technical detail has UX consequences: as of September 2026, MDN notes that when server-sent events are not used over HTTP/2, browsers cap open connections at a very low number (6) per browser and domain. A user with your app open in several tabs can hit that cap and see responses stall.

Design rules for streamed output:

  • Do not fight the reader. Auto-scroll to follow new text only while the user is at the bottom. If they scroll up to reread, stop moving the page and offer a "jump to latest" control.
  • Keep the layout stable. Reserve space for things that appear at the end, such as source lists and action buttons, so they do not shove content around when they load.
  • Render formatting carefully. Half-finished markdown, such as a list that has just started or a code block without its closing fence, should not flicker between styles. Hold back structural elements until they are complete.
  • Mark completion clearly. Show when the response is finished. Enable copy, insert, or share only then, or label the result as incomplete.
  • Make stopping safe. When someone stops generation, keep what was produced and mark it as stopped rather than discarding it.

Progress for long tasks

Some AI work, such as research across many documents, batch processing, or a multi-step agent run, takes far longer than a chat reply. Nielsen Norman Group's guidance on progress indicators reserves looped animations like spinners for fast actions of roughly 2 to 10 seconds, and recommends percent-done indicators for waits of 10 seconds or more.

AI tasks rarely know their percentage complete, but they usually know their steps. Use that:

  • Show the steps as a list with the current one highlighted: "Searching sources," "Reading 8 of 20 results," "Drafting summary."
  • For batch jobs, show items finished out of items total.
  • Show a time estimate only if you can make an honest one. A wrong estimate can do more harm than none.
  • Let people leave. For anything that runs more than a minute or so, offer to notify them when it finishes, and make the result easy to find afterward.
  • Always offer cancel, and say what happens to work already completed.

Partial results are results

When a long task fails partway through, the worst response is to discard everything and show a generic error. Design for partial success instead:

  • Keep and show whatever finished, clearly labeled as incomplete.
  • Name exactly what did not finish. "3 files could not be read" is actionable. "Something went wrong" is not.
  • Offer to retry only the failed part, without rerunning what already worked.
  • When generated text is cut off by an error or a length limit, show where it stopped and offer to continue from there.

Error messages for AI-specific failures

A good error message says what happened, what was kept, and what the person can do next. Three failures are common enough in AI products to deserve their own copy.

Timeouts

Say that the request took too long, without implying the user did anything wrong. Keep their input intact so retrying takes one click. If certain requests time out repeatedly, suggest a smaller scope, such as fewer documents or a shorter date range, and make that suggestion a button rather than advice.

Refusals

A refusal is not a crash, so do not style it like one: no red banner, no error icon. Say plainly that this is something the feature will not help with, without lecturing and without blaming the user. Where you can, point to what it can do instead, or where the person can get help. Keep refusal wording consistent across the product, so people learn where the boundary is instead of rephrasing to probe it.

Rate limits and quotas

Rate limiting has a standard HTTP signal. The 429 Too Many Requests status code, defined in RFC 6585, means the client has sent too many requests in a given amount of time, and the server may include a Retry-After header saying how long to wait. Carry that information through to the interface:

  • If you know when the limit resets, show it: "You can send more requests in 2 minutes," ideally with a countdown.
  • Separate a personal quota ("You've used this month's allowance") from system load ("We're handling a lot of requests right now"). They call for different actions.
  • Preserve whatever the user typed, so nothing is lost while they wait.
  • Retry automatically after short waits, and tell the user you are doing it.

Empty states that teach what to ask

An empty box with a blinking cursor asks users to guess what the feature can do. The empty state is your best chance to teach capability without a tutorial.

  • Offer starter requests built from the user's own context. "Summarize this week's open bugs" teaches more than "Ask me anything," because it shows both the scope and a phrasing that works.
  • Show the shape of a good request. Examples that include specifics, such as a time range, an output format, or an audience, teach people to include those details themselves.
  • Mark the edges. One line about what the feature cannot see or do heads off the first failure.
  • Treat "no results" as an empty state too. When a request comes back empty, suggest a broader or reworded version the user can run with one click.
  • Let suggestions mature. Once someone has used the feature, replace generic starters with their own recent or frequent requests.

Build a state inventory before launch

List every state before you design screens, and give each one copy and an action. A starting inventory:

StateWhat the user seesWhat the user can do
Submitted, waitingTheir request and a status lineCancel
StreamingA growing responseStop, keep reading
Long task runningA step list or item countsLeave and get notified, cancel
Partial failureCompleted work plus what failedRetry the failed part
TimeoutPlain explanation, input keptRetry, narrow the scope
RefusalWhat it will not do, and alternativesRephrase, get help elsewhere
Rate limitedWhen they can try againWait, or change plans if you offer that
EmptyStarter requests and a scope notePick a starter or type their own

Review this inventory with engineering early. Several of these states depend on information only the backend has, such as step progress, partial output, or a Retry-After value, and that information is far easier to expose from the start than to retrofit after launch.

More from aiurx.com