HTTP status errors: handling 4xx and 5xx responses
A status error means the HTTP round trip worked — connection, TLS, request, response all succeeded — and the server used the status code to tell you something. Whether your client throws for it (axios rejects outside 2xx by default; fetch does not) is library policy, not protocol.
Whose bug is it?
400 Bad Request | Yours: malformed body, wrong content type, failed validation. Read the response body — most APIs say exactly which field. |
401 / 403 | Yours: missing/expired credentials (401) or valid credentials without permission (403). See the authentication guide. |
404 | Ambiguous: wrong URL or genuinely absent resource. APIs also use it to hide resources you can't access. |
409 / 422 | Yours, semantically: version conflict or well-formed-but-invalid input. |
429 Too Many Requests | You're being rate limited. Honor Retry-After; back off, don't hammer. |
500 | Theirs: an unhandled server error. Retrying rarely helps; report with a request ID if the API returns one. |
502 / 503 / 504 | Infrastructure: a proxy couldn't reach a healthy backend (502), the service is overloaded or deploying (503), or the upstream timed out (504). Transient by nature — the retryable family. |
Get the whole story
The status code is the headline; the response body and headers carry the actual
diagnosis. Log them on failure — an error handler that logs only "Request failed with status
code 400" discards the field-level detail the server already sent you. In axios that body is
error.response.data; in fetch you must read it before throwing your own error.
Retry policy in one paragraph
Retry 429 (respecting Retry-After), 503, and
502/504 for idempotent requests, with exponential backoff and a
cap. Never auto-retry 4xx — the request is wrong, and resending it is a louder way to be
wrong. Treat an unexpected 4xx in production as a bug report about your own request
construction, and an unexpected 5xx spike as the other side's incident: alert, degrade
gracefully, and stop sending non-essential traffic while it lasts.
Documented occurrences
3 analyzed errors across 2 libraries match this failure class. Each links to the thrown message, its source line, and documented fixes.
axios/axios
- ERR_BAD_RESPONSE: maxContentLength size of ${maxContentLength} exceeded
- ERR_BAD_RESPONSE: maxContentLength size of ${limit} exceeded