A request times out. The server might have done nothing, finished the work, or reached the external provider and lost the reply. One red error banner can’t describe all three.
The retry button needs to account for that uncertainty. If the operation can charge money or send a message, first establish whether the original attempt succeeded. A provider idempotency key helps where supported; elsewhere, you need a reconciliation path.
For longer jobs, I want progress saved between stages. Uploading a file again because its export failed is needless punishment. Store the user’s request separately from execution attempts so a failed attempt doesn’t destroy the work they asked for.
The error message should match the state you actually know. “We haven’t confirmed the payment yet” is different from “the payment was declined.” Preserve the input and include a reference support can trace.
I try to design this before adding the final polish. It changes the data model, the worker and the interface. Leaving it until later usually means the retry button becomes an optimistic guess.