INTERFACE STATES
Make retry behavior visible when a request fails
Separate failed, pending and unknown request outcomes, and decide when a retry is safe using request identity, deduplication or a status lookup.
Failed, pending and unknown are three different outcomes. A confirmed failure means the server reliably establishes that the operation did not complete. A generic error response alone may not establish that. Pending means the request is still in progress. Unknown means the request was sent and no answer arrived, so the work may or may not have happened. A single 'Something went wrong. Retry' message treats all three the same.
For reads, that is usually harmless. For writes, a careless retry can do the work twice. This guide covers how to decide when to retry and how to show that decision.
Drafting was AI-assisted. Tallyboard, invoice 2041 and every finding are fictional. Request identity, deduplication and status lookup are design options for your own system, not functions of any tool here.
Label the outcome before offering an action
Give each state its own message and action:
- Failed: say what was rejected and whether changing the input will help.
Pending: show that the request is underway and prevent a duplicate click.
Unknown: say plainly that the result could not be confirmed, and do not present it as a failure.
Ask whether repeating the request is safe
MDN defines an idempotent method as one where sending the same request once or several times leaves the server in the same state. GET, HEAD, PUT and DELETE are defined that way; POST is not. The property is about server state, not identical responses. A server can still implement a method in a way that breaks it.
So the method name is a starting point, not proof. If a write might not be idempotent in practice, an unknown outcome should not lead to an automatic or one-click retry.
Sources: MDN: Idempotent.
Choose a design that makes retries safe
These three parts are worth discussing together with whoever owns the server. A request identifier alone does not prevent duplicate side effects; the server must enforce deduplication, including concurrent requests and repeats while the original is pending. They are design patterns, not something the review tool on this site performs.
- Request identity: the client attaches one identifier to each user intent and reuses it on retry.
Server-side deduplication: the server remembers identifiers and returns the original result when a repeat arrives.
Status lookup: the client asks what happened to a request before deciding to resend it.
Each option needs decisions about how long identifiers are kept and what happens while the original request is still running.
Treat 429 as a request to wait
MDN describes 429 Too Many Requests as the server signalling that the client sent too many requests in a given period. The response may include a Retry-After header that says how long to wait.
In the interface, explain the pause. When a Retry-After value is present, keep the action unavailable until that time passes. Make sure automatic retries do not add load. This guide sets no retry counts or delays; those belong to the service's own limits and documentation.
Sources: MDN: 429 Too Many Requests.
Walk through a fictional invoicing app
In the fictional Tallyboard app, a user presses Send on invoice 2041, and the connection drops before a response arrives. The original screen said 'Failed' and offered a Retry button. A retry could have emailed the customer twice.
The revised screen says 'We could not confirm whether invoice 2041 was sent.' Its button is Check status, which queries the server by the request identifier. If the server reports the invoice as sent, the screen updates. If the server has no record, a Send button appears that reuses the same identifier, so deduplication can catch an original request that arrives late.
Separately, an export returns 429 with Retry-After. The screen explains that exports are paused briefly and re-enables the button once the wait has passed.
Finish with a review checklist
Run this checklist against one failing request at a time. It does not cover offline queues, background sync or multi-service transactions. Every label must match what the server actually guarantees, so confirm the behavior with the server's owners. The last column shows the fictional Tallyboard review.
Retry review for one failing request
- Check: Outcome labels; Look for: Failed, pending and unknown look different; Tallyboard finding: Unknown was shown as failed; relabelled
- Check: Write safety; Look for: Retry offered only where repeats are harmless; Tallyboard finding: Send had a one-click retry; replaced
- Check: Request identity; Look for: The same identifier is reused on any resend; Tallyboard finding: Added to the send request
- Check: Status path; Look for: A way to learn the result before resending; Tallyboard finding: Check status button added
- Check: Rate limits; Look for: 429 handled, and Retry-After respected when present; Tallyboard finding: Export button waits