← All topics/Networking & data

Question 2

Errors, retries, and UX

How do you handle network failures, retries, and error states in a way that provides a good user experience?

Answer outline

Classify each failure first, then react to it at the layer that can do something useful. Four rules follow from that:

  1. 1.Classify at the boundary: map raw URLError values and HTTP status codes into typed app-level categories (transient, client, server, decoding). Feature code switches on the category and never reads a status code.
  2. 2.Retry selectively: retry transient failures such as timeouts and connectivity loss with exponential backoff, and fail fast on decoding errors and most client errors in the 400 range. The exceptions are 401, where you refresh the token and retry once, and 429, where you wait out the Retry-After interval.
  3. 3.Check idempotency on writes: a request is idempotent when sending it twice has the same effect as sending it once, so retrying a GET is safe. Retrying a POST that creates data may not be, so send a client-generated request ID and let the server detect duplicates.
  4. 4.Degrade gracefully: show cached data when you have it, offer a manual retry, and don't block the whole screen for a failure that affects one component.

Keep all of this in one place. A single retry policy and a single error mapper are easier to test and keep consistent than checks scattered across features.

Principles

  • One retry policy and one error mapper serve every feature, so a fix in either applies everywhere at once.
  • Retry only transient failures, with exponential backoff (a delay that doubles up to a cap) plus jitter so clients don't retry in lockstep.
  • Retry a write only when it's idempotent or carries a request ID the server can deduplicate.
  • Show the user a meaningful message and a way forward, never a raw status code.