Last active
December 14, 2025 02:46
-
-
Save isocroft/fbb87a7f865e9f6dbff3c577f9cfb65b to your computer and use it in GitHub Desktop.
Utility to help extract clear, meaningful, human-oriented error messages (as opposed to generic & cryptic error messages) from an axios error object on a web frontend application to aid debugging on the backend
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import axios, { AxiosError, AxiosResponse, AxiosRequestConfig } from "axios"; | |
| const expandOnError = (errorMessage: string, errorCode?: string, errorResponse?: AxiosResponse) => { | |
| if (errorMessage === "Network Error" && Boolean(!errorResponse)) { | |
| /* @HINT: The message returned below simply means that a CORS error occured OR the name resolution failed */ | |
| return errorCode === undefined | |
| ? "We are currently updating our systems... Please try again later" | |
| : "Your ISP seems to have some other network-related issues"; | |
| } | |
| return "The browser restricted access to the server response! Please contact admin"; | |
| }; | |
| const isCORSViolation = (request: XMLHttpRequest, config?: AxiosRequestConfig) => { | |
| const frontendURIHost = window.location.host; | |
| const backendBaseURL = new URL(config?.baseURL || config?.url || "https://x.yz"); | |
| const backendURIHost = backendBaseURL.host; | |
| const isCrossDomainRequest = backendURIHost !== "x.yz" && frontendURIHost !== backendURIHost; | |
| let hasAccessControlOnOrigin = false; | |
| const requestHasValidStatus = Boolean((request.status >= 200 && request.status <= 508)); | |
| const contentType = request.getResponseHeader("Content-Type"); | |
| if (isCrossDomainRequest) { | |
| let allowedOrigin = ""; | |
| try { | |
| if (request.withCredentials) { | |
| allowedOrigin = request.getResponseHeader("Access-Control-Allow-Origin") || ""; | |
| } | |
| /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ | |
| } catch (_) { allowedOrigin = ""; } | |
| if (allowedOrigin.trim() === "*") { | |
| return true; | |
| } else { | |
| hasAccessControlOnOrigin = Boolean(allowedOrigin.trim() === backendBaseURL.origin.trim()); | |
| } | |
| } | |
| return ((isCrossDomainRequest && requestHasValidStatus) && (!hasAccessControlOnOrigin && contentType !== null)); | |
| }; | |
| export const getMessageFromAxiosError = (error: AxiosError) => { | |
| let message = ""; | |
| const isNotCORSViolation = !isCORSViolation(error?.request as XMLHttpRequest, error?.config); | |
| /* @CHECK: https://axios-http.com/docs/handling_errors */ | |
| /* @SEE: https://www.intricatecloud.io/2020/03/how-to-handle-api-errors-in-your-web-app-using-axios/ */ | |
| /* @HINT: These are the varying ranges of error(s) that can occur when making async HTTP requests */ | |
| const isServerResponseEmpty = Boolean(!error?.response) && ((Boolean(error?.request) && isNotCORSViolation) && error?.code !== "ERR_NETWORK"); | |
| const isServerTimedOut = error?.code === "ECONNABORTED" || error?.code === "ETIMEDOUT"; | |
| const isServerUnreachable = error?.code === "ECONNREFUSED"; | |
| const isClientOffline = window !== undefined ? !window.navigator.onLine : false; | |
| const errorMessagesMap = { | |
| unreachable: "Our systems are unreachable! Please try again later", | |
| timeout: "Our systems request(s) timed out! Please try again", | |
| indeterminate: "Something went wrong! Please try again", | |
| offline: "Your internet is unstable! Please check and try again" | |
| }; | |
| switch (true) { | |
| case isClientOffline: | |
| message = errorMessagesMap["offline"]; | |
| break; | |
| case isServerUnreachable: | |
| message = errorMessagesMap["unreachable"]; | |
| break; | |
| case isServerTimedOut: | |
| message = errorMessagesMap["timeout"]; | |
| break; | |
| case isServerResponseEmpty: | |
| message = "Our systems response returned empty! Please try again"; | |
| break; | |
| default: | |
| message = Boolean(error?.response) | |
| ? errorMessagesMap["indeterminate"] | |
| : expandOnError(error.message, error?.code, error?.response); | |
| } | |
| return message; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.