HTTP API Errors 401, 403, 429, and 5xx: Diagnosis and Safe Retries
Diagnose HTTP API errors 401, 403, 429, and 5xx. Understand Retry-After, backoff, timeouts, and idempotency so retries do not duplicate operations.
Checked on October 2, 2026. Based on HTTP standards and official documentation. The retry policy is a local simulation; its timing values are not universal recommendations for every API.
An application fetches API data. Its first request fails, so a developer adds automatic retries. Errors appear less frequent, but duplicate orders emerge and the server receives more requests while already overloaded. The issue is not just attempt count: the application has not distinguished authentication failures, rate limits, temporary outages, and operations that may already have succeeded.
Short answer: inspect status, headers, and the provider's error code before deciding what to do. Correct credentials or permissions for 401/403; regulate request rate for 429; investigate server failures for 5xx. Retry only when the cause is appropriate and repeating the operation is safe. A client timeout does not establish that the server never processed the request.
Start with comparable evidence
Record the method, endpoint without sensitive parameters, UTC time, HTTP status, request ID, and duration. Include the provider's application error code. Avoid logging bearer tokens, API keys, personal information, or entire bodies. A request ID usually helps provider support more than a screenshot saying only "failed."
Determine whether an HTTP response arrived. DNS errors, TLS failures, disconnections, and cancellations require different investigations from a received 401. If a browser reports only a network failure, do not invent a 500 status. Inspect Network activity and backend logs to identify the failing layer.
Separate HTTP success from business-task success, too. Depending on the contract, 200 can accompany partial results or an unfinished task. A 202 means accepted for processing, not proof of eventual completion. For asynchronous work, retain the task ID and follow the documented status endpoint.
Diagnosis: the first action matters more than repetition
| Status | Core meaning | First investigation | Repeat an identical request? |
|---|---|---|---|
| 401 | Valid authentication credentials are unavailable for the resource | Missing, expired, wrong-environment token or authentication scheme | Usually unhelpful before credential correction |
| 403 | Server understands but refuses the request | Scope, role, organization policy, resource access | Unhelpful if the refusal remains unchanged |
| 429 | Too many requests in a period | Affected limit, concurrency, headers, provider code | Possibly after waiting and lowering the rate |
| 500 | Unexpected server condition | Request ID, error pattern, service status, provider contract | Only under a bounded policy and safe operation |
| 502 | Gateway received an invalid upstream response | Gateway, origin, outage pattern | May be temporary, but not always |
| 503 | Service temporarily cannot handle the request | Maintenance, load, Retry-After |
Often worth considering within limits |
| 504 | Gateway did not receive an upstream response in time | Upstream duration and operation status | The operation's outcome may remain unknown |
Authentication semantics are documented in MDN 401 and MDN 403. Server errors have separate references for 500, 502, 503, and 504. Suggested actions are editorial applications, not claims that every provider uses identical supplementary codes.
The name 401 "Unauthorized" can be confusing because its central issue is authentication. A 403 does not necessarily prove a successful login: other policies can cause refusal. Consult the provider's contract for the specific cause. Randomly changing endpoints is not an appropriate way around denied permissions.
Why are timeouts dangerous for writes?
Imagine a client sends POST /orders, the server saves an order, and the connection drops before the response arrives. The client sees a timeout. A new POST can create a second order. The operation succeeded, while delivery of its result failed.
RFC 9110 section 9.2.2 defines idempotency through the intended server effect. PUT, DELETE, and semantically safe methods are idempotent. Repeated responses need not be identical: an initial deletion may succeed, while another reports that the resource is absent.
POST does not become idempotent because a developer labels it "retryable." Some APIs support idempotency keys or deduplication. Read their scope, lifetime, and payload rules. Preserve the same key for attempts at the same operation according to that contract. Creating a new key on each attempt can make every request a new operation.
Without a repetition guarantee, use business-operation IDs and supported status checks. Searching only by amount or title is unreliable because legitimate separate operations can share those values. After a timeout, "outcome unknown" can be more accurate than "failed" followed by an instruction to submit again.
Read 429 and Retry-After correctly
RFC 6585 section 4 defines 429 for excessive requests and permits Retry-After. It does not mandate one user-identification or counting method. A provider may apply limits to an account, token, endpoint, or another dimension.
Retry-After can specify seconds or an HTTP date. Do not assume Number(header) covers both. For a date, calculate the difference from now, account for client clock accuracy, and do not use negative waits.
If the requested wait exceeds the task deadline, stop or schedule a later attempt. Reducing a 120-second instruction to two seconds to keep an interface fast repeats the violation. The interface can show a pending state without holding the user's connection throughout the wait.
Not every 429 recovers after a short delay. A body indicating daily quota, spending limits, or required account action should guide recovery. Adding workers can worsen the problem. Manage queues and concurrency across the application, not only inside the one function receiving the error.
Backoff, jitter, and attempt budgets
Backoff increases the delay between attempts. Jitter varies the timing so many clients do not retry simultaneously. The Cloud Storage retry guide discusses exponential backoff, idempotency, and excessive retries. Its numeric settings are product-specific, not a standard for every API.
The following code calculates a simulated decision and delay. It sends no requests, does not parse Retry-After, and cannot establish endpoint idempotency. safe_to_repeat must come from the operation contract, not a guess based on status.
import random
def retry_delay(status, safe_to_repeat, attempt, rng):
# attempt=0 is the first retry; allow at most three retries.
if not safe_to_repeat or status not in {429, 502, 503, 504}:
return None
if attempt < 0 or attempt >= 3:
return None
ceiling = min(8.0, 0.5 * (2 ** attempt))
return rng.uniform(0.0, ceiling)
rng = random.Random(17)
assert retry_delay(401, True, 0, rng) is None
assert retry_delay(503, False, 0, rng) is None
assert retry_delay(503, True, 3, rng) is None
assert 0 <= retry_delay(503, True, 2, rng) <= 2.0
print("Simulation rules passed")
This conservative example excludes 500 deliberately. Some providers document it as transient; another application may repeatedly produce it because of a deterministic bug. Add it only after understanding the contract. Three retries and a 0.5-second base are exercise choices, not performance findings.
Production handling also needs an overall deadline, per-request timeouts, and cancellation. SDK retries combined with application retries can multiply attempts. Inspect both layers and decide who controls the policy. Counting only the application loop can understate actual requests.
Check the response before parsing JSON
The MDN Fetch guide explains that HTTP errors such as 404 do not automatically reject fetch(). Inspect response.ok or status, then handle the body according to the contract. Gateway HTML can otherwise produce a JSON error masking the original HTTP issue.
For successful responses without bodies, such as 204, do not force JSON parsing. On errors, inspect provider codes carefully and bound retained body size. Practice with invalid JSON diagnosis and the JSON Formatter.
Test scenarios before enabling retries
| Simulated scenario | Expected behavior |
|---|---|
| Incorrect token produces repeated 401 | Stop and provide authentication recovery |
| GET receives 503, then 200 | Bounded retry under the policy |
| POST times out after storage succeeds | Reconcile or deduplicate; avoid a new operation |
| 429 requests a wait beyond the deadline | Defer or report the limit; do not retry early |
| SDK and application both retry | Actual requests remain within the intended budget |
| Gateway returns HTML | Report the HTTP failure without blaming user JSON |
Use a mock server that tracks requests and operations separately. Four requests can represent one deduplicated operation or four accidental operations. Measure recovery and latency under the real policy after correctness is established.
Sources and application limits
The primary standards are HTTP Semantics, RFC 9110 and Additional HTTP Status Codes, RFC 6585. MDN explains client behavior, while Cloud Storage provides a product-policy example. Sources were checked on the date above.
This article does not assign provider-specific quotas, retry timing, or idempotency-key support. Check your endpoint documentation. For AI applications, also read safe API key storage so connection recovery does not expose credentials.