Catching Axios Unhandled Promise Rejections

Axios is an asynchronous HTTP client that relies entirely on JavaScript Promises, meaning any network failure, non-2xx HTTP status code, or execution error will reject the promise. When an application fails to handle these rejections, the JavaScript runtime raises an unhandled promise rejection error, which can cause Node.js applications to terminate or browser scripts to fail silently. Catching and resolving these rejections requires a combination of local error handling, centralized Axios interceptors, and environment-level safety nets.

1. Local Request-Level Error Handling

The most direct way to handle Axios errors is at the invocation point. Depending on whether you use async/await syntax or standard Promise chains, you must provide a catch block.

Using async/await with try...catch

Wrap the axios call inside a try...catch block. This ensures synchronous and asynchronous exceptions are caught locally:

import axios from 'axios';

async function fetchData(url) {
  try {
    const response = await axios.get(url);
    return response.data;
  } catch (error) {
    // Inspect Axios error structure
    if (error.response) {
      // The server responded with a status outside the 2xx range
      console.error(`Server Error: ${error.response.status}`, error.response.data);
    } else if (error.request) {
      // The request was made but no response was received
      console.error('Network Error: No response received', error.request);
    } else {
      // Something happened in setting up the request
      console.error('Request Setup Error:', error.message);
    }
    // Return a fallback or rethrow a standardized error
    return null;
  }
}

Using Promise Chaining (.then() and .catch())

If you are using standard Promise syntax, always append a .catch() handler to the end of the chain:

axios.get('https://api.example.com/data')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error('Request failed:', error.message);
  });

2. Centralized Handling with Axios Interceptors

To manage rejected promises globally across all Axios instances without repeating try...catch blocks, use response interceptors. Interceptors can process errors, refresh expired tokens, log telemetry, or standardize output before the error reaches calling code.

import axios from 'axios';

const apiClient = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000,
});

// Add a response interceptor
apiClient.interceptors.response.use(
  (response) => {
    // Return successful responses as-is
    return response;
  },
  (error) => {
    // Handle specific global status codes (e.g., 401 Unauthorized)
    if (error.response && error.response.status === 401) {
      console.warn('Session expired. Redirecting to login...');
    }

    // Always return a rejected promise so local handlers know an error occurred
    return Promise.reject(error);
  }
);

Note: If an interceptor does not return a rejected promise (e.g., it returns a resolved value), downstream callers will treat the response as a success.


3. Environment-Level Global Catch Handlers

As a last line of defense, configure the JavaScript runtime to intercept unhandled promise rejections that bypass local and interceptor logic.

In Node.js

Node.js provides the unhandledRejection event on the global process object:

process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
  // Optional: Gracefully restart the service or log to an observability platform
});

In the Browser

Modern browsers expose the unhandledrejection event on the window object:

window.addEventListener('unhandledrejection', (event) => {
  console.error('Unhandled Promise Rejection:', event.reason);
  // Prevent the default browser console error output if desired
  event.preventDefault();
});

Summary Checklist for Preventing Rejections

  1. Always wrap await axios calls in a try...catch block.
  2. Always append .catch() when using .then() syntax.
  3. Configure Axios response interceptors for cross-cutting concerns like authentication refreshes and logging.
  4. Implement runtime safety nets (process.on or window.addEventListener) to monitor and log unhandled exceptions.