Error Handling in Axios vs Fetch API Explained
When making HTTP requests in modern JavaScript applications, handling
errors correctly is crucial for application stability and user
experience. The fundamental difference between Axios and the native
Fetch API regarding response statuses lies in how they treat HTTP error
codes (such as 404 or 500). Axios automatically rejects promises when an
HTTP status code falls outside the 2xx range, routing them directly to
the catch block. In contrast, Fetch resolves the promise
normally for any valid HTTP response regardless of the status code,
requiring developers to manually verify the status and throw errors
themselves.
Error Handling in Fetch API
The native Fetch API only rejects a promise when a network failure
occurs, such as a lost internet connection, a DNS lookup failure, or a
blocked CORS request. If the server responds with a
404 Not Found, 401 Unauthorized, or
500 Internal Server Error, Fetch considers the request
completed successfully and resolves the promise.
To handle HTTP error statuses in Fetch, you must manually inspect the
ok property or the status code on the returned
Response object.
async function fetchUserData() {
try {
const response = await fetch('https://api.example.com/users/999');
// Fetch does not automatically throw for 4xx or 5xx
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Fetch Error:', error.message);
}
}If !response.ok is omitted, the code will proceed to
parse the response body (like response.json()), which often
leads to unexpected syntax errors if the server returned an HTML error
page or an unexpected error payload.
Error Handling in Axios
Axios provides a more automated approach. By default, it rejects the
promise for any HTTP response status code that falls outside the
2xx range (status < 200 or status >= 300). This
triggers the catch block immediately without requiring
manual status validation.
When an HTTP error occurs, Axios creates an error object that
contains rich debugging information, accessible via
error.response.
import axios from 'axios';
async function fetchUserData() {
try {
const response = await axios.get('https://api.example.com/users/999');
console.log(response.data);
} catch (error) {
if (error.response) {
// The server responded with a status code outside the 2xx range
console.error('Status Code:', error.response.status);
console.error('Error Data:', error.response.data);
} else if (error.request) {
// The request was made but no response was received (Network error)
console.error('Network Error:', error.request);
} else {
// Something happened in setting up the request
console.error('Request Setup Error:', error.message);
}
}
}Axios also allows you to customize which HTTP status codes should
throw an error using the validateStatus configuration
option:
axios.get('/users/999', {
validateStatus: function (status) {
return status < 500; // Reject only if status is 500 or higher
}
});Summary of Key Differences
- Promise Rejection Trigger: Fetch rejects
only on network failures. Axios rejects on network failures
and any HTTP status code outside the
200–299range by default. - Status Checking: Fetch requires checking
response.ok(orresponse.status) manually. Axios checks this automatically. - Error Payloads: In Fetch, you must parse the
response body manually when an error status is received. In Axios, the
parsed server response is automatically attached to
error.response.data. - Configurability: Axios allows custom HTTP status
validation through
validateStatus, whereas Fetch requires custom wrapper logic to achieve the same behavior.