axios-retry
semver
>=1.0.0postconditions8functions7last verified2026-06-23coverage score78%Postconditions — what we check
- axiosRetry · axios-retry-config-onlyinfoWhenThis function configures retry behavior but does not throw errorsThrows
N/A - Configuration functionRequired handlingaxios-retry() is a configuration function that does not throw. The actual error handling requirements are for the UNDERLYING AXIOS METHODS. After retries are exhausted, axios will throw - users must still use try-catch. See the axios Nark profile for specific error handling requirements.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - axios.get/post/put/delete (with retry) · axios-retry-exhaustederrorWhenAll retry attempts have been exhaustedThrows
AxiosError (same as standard axios)Required handlingCaller MUST wrap axios calls in try-catch block even when axios-retry is configured. axios-retry only retries failed requests - it does not prevent errors from being thrown. After the final retry fails, the error is re-thrown exactly as axios would throw it. The retry logic is transparent to error handling - try-catch is still required.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - axiosRetry (validateResponse option) · validate-response-overrides-validate-statuserrorWhenvalidateResponse callback is set in axiosRetry configThrows
N/A — behavioral configuration change, not a throwRequired handlingMUST NOT set validateResponse without understanding it overrides axios's validateStatus for ALL requests on that instance. With validateResponse set, axios no longer resolves successful 2xx responses unless validateResponse returns true for them. Callers relying on axios's default behavior (resolve 2xx, reject non-2xx) will have all responses routed to the error interceptor if validateResponse is configured but doesn't explicitly return true for 2xx status codes. Pattern to avoid (breaks all responses): axiosRetry(instance, { validateResponse: (res) => res.status !== 429 // 200-OK also goes through error path! }); Correct pattern: axiosRetry(instance, { validateResponse: (res) => res.status >= 200 && res.status < 300 });costhighin prodsilent failureusers seelost datavisibilitysilentSources[2] - axiosRetry (POST/PATCH not retried by default) · post-patch-not-retried-by-defaultwarningWhenaxiosRetry is configured with default retryCondition and caller makes POST or PATCH requests expecting retry behaviorThrows
AxiosError (thrown on first failure, no retries attempted)Required handlingMUST explicitly configure retryCondition to retry POST/PATCH if that is the intent. The default retryCondition (isNetworkOrIdempotentRequestError) NEVER retries POST or PATCH — not on network errors, not on 5xx errors. This is intentional (POST is not idempotent — retrying can cause duplicate records), but developers often misconfigure axiosRetry globally and assume POST requests are covered. To retry POST on network errors only (safe for idempotent backends): axiosRetry(instance, { retryCondition: (error) => { return axiosRetry.isNetworkError(error); // Network-only, not 5xx } }); To retry POST on any error (requires idempotent backend): axiosRetry(instance, { retryCondition: axiosRetry.isRetryableError // 5xx + network });costmediumin proddegraded serviceusers seedegraded performancevisibilitysilentSources[3] - axiosRetry (global timeout behavior) · timeout-global-not-per-retrywarningWhenaxiosRetry is configured with a timeout and shouldResetTimeout is not set to true (default false)Throws
AxiosError with code ECONNABORTED (when global timeout expires)Required handlingMUST set shouldResetTimeout: true if you want each retry attempt to have the full timeout budget. Without it, retries on slow servers will exhaust the timeout before all retries run. Example where retries never help (timeout too tight): axios.defaults.timeout = 3000; // 3 second timeout axiosRetry(axios, { retries: 3 }); // First attempt takes 2.8s → only 0.2s left for 3 retries → immediate timeout Correct pattern for retry with full timeout per attempt: axiosRetry(axios, { retries: 3, shouldResetTimeout: true, // Each attempt gets full 3s timeout retryDelay: axiosRetry.exponentialDelay }); This behavioral change was introduced in v3.0.0 (2017-08-13) as a deliberate design decision to prevent retries from extending beyond the intended timeout.costmediumin proddegraded serviceusers seedegraded performancevisibilitysilent - axiosRetry (onRetry async error swallowing) · on-retry-error-replaces-original-errorwarningWhenonRetry callback throws an error (e.g., token refresh rejects)Throws
Error thrown by onRetry callback (replaces original AxiosError)Required handlingonRetry callbacks MUST handle their own errors. If onRetry throws, the error propagated to the catch block is the onRetry error (not the original request AxiosError). This makes error diagnosis difficult. Token refresh pattern that silently loses original error: axiosRetry(instance, { onRetry: async (retryCount, error, config) => { if (error.response?.status === 401) { const token = await refreshToken(); // If this throws, original error is lost config.headers.Authorization = Bearer ${token}; } } }); Correct pattern with error preservation: axiosRetry(instance, { onRetry: async (retryCount, error, config) => { try { if (error.response?.status === 401) { const token = await refreshToken(); config.headers.Authorization = Bearer ${token}; } } catch (refreshError) { console.error('Token refresh failed:', refreshError); // Re-throw to abort retries, or handle silently to continue throw refreshError; } } });costmediumin prodsilent failureusers seeauthentication failurevisibilitysilentSources[3] - axiosRetry (onRetry async error swallowing) · retry-condition-error-swallowedwarningWhenretryCondition callback throws (e.g., error in custom retry logic)Throws
N/A — error is silently swallowed, retry returns falseRequired handlingCustom retryCondition callbacks that throw have their errors silently discarded. The error is caught, returning false (no retry). This means broken retryCondition logic causes silent retry disabling with no log. Broken retryCondition (error silently swallowed): axiosRetry(instance, { retryCondition: (error) => { return someUndefinedHelper.check(error); // TypeError swallowed silently // Result: retries disabled, no indication why } }); MUST test retryCondition logic thoroughly — errors in it disable retries silently in production.costlowin prodsilent failureusers seedegraded performancevisibilitysilentSources[3] - axiosRetry (onMaxRetryTimesExceeded async error swallowing) · on-max-retry-times-exceeded-error-replaces-original-errorwarningWhenonMaxRetryTimesExceeded callback throws an error (e.g., alerting fails, fallback rejects, logging service unreachable)Throws
Error thrown by onMaxRetryTimesExceeded callback (replaces original AxiosError)Required handlingonMaxRetryTimesExceeded callbacks MUST handle their own errors internally via try-catch. If they throw, the error reaching the caller's catch block is the callback error — NOT the original retry-exhausted AxiosError. This silently destroys the failure diagnostic ("the API returned 500 three times" becomes "alerting service rejected"). Anti-pattern that swallows the real failure cause: axiosRetry(instance, { retries: 3, onMaxRetryTimesExceeded: async (error, retryCount) => { await alertingService.notify(error); // If this throws, caller sees alerting error await fallbackDb.write({ failed: true }); // Same hazard } }); Correct pattern — preserve original error context: axiosRetry(instance, { retries: 3, onMaxRetryTimesExceeded: async (error, retryCount) => { try { await alertingService.notify(error); await fallbackDb.write({ failed: true }); } catch (sideEffectError) { console.error('Side-effect failed during max-retry handler:', sideEffectError); // Do NOT re-throw — preserves the original AxiosError for the caller } } }); Operational consequence: production incident triage sees the alerting error first and walks the wrong call tree. The 503 from upstream is invisible until log archaeology surfaces the original interceptor trace.costmediumin prodsilent failureusers seedegraded performancevisibilitysilent
Sources
Every postcondition cites at least one of these. Numbered to match the footnotes above.
- [1]github.com/softonic/axios-retryhttps://github.com/softonic/axios-retry#usage
- [2]github.com/softonic/axios-retryhttps://github.com/softonic/axios-retry/blob/master/CHANGELOG.md
- [3]github.com/softonic/axios-retryhttps://github.com/softonic/axios-retry#options
- [4]github.com/softonic/axios-retryhttps://github.com/softonic/axios-retry/blob/master/src/index.ts
Need a different package?
Request a profile