Handling Non-Standard HTTP Status Codes in Axios

This guide explains how to properly handle non-standard HTTP status codes using the Axios HTTP client. By default, Axios treats any HTTP response code outside the 2xx range as an error and rejects the request promise. By leveraging the validateStatus configuration option and response interceptors, you can customize how Axios interprets status codes, process non-standard or proprietary API responses directly in your resolve logic, and maintain predictable application flow.


Understanding the Default Axios Behavior

Axios determines whether a request promise should be resolved or rejected using a built-in configuration option named validateStatus. The default behavior is defined as follows:

validateStatus: function (status) {
  return status >= 200 && status < 300;
}

Whenever a server returns a non-standard HTTP code (such as vendor-specific codes like Cloudflare's 520–527, custom 9xx codes, or unassigned status integers), Axios triggers a rejection and throws an AxiosError if the code falls outside the 200–299 range.


Method 1: Using the validateStatus Option

The most direct and standard way to handle non-standard codes is by overriding validateStatus in the request config. This allows non-standard codes to resolve successfully in the .then() chain or try block rather than throwing an exception.

Per-Request Configuration

You can pass validateStatus directly inside the request configuration object:

import axios from 'axios';

async function requestWithCustomCodes() {
  try {
    const response = await axios.get('https://api.example.com/custom-endpoint', {
      validateStatus: function (status) {
        // Accept standard 2xx codes plus custom non-standard codes (e.g., 299, 418, 999)
        return (status >= 200 && status < 300) || status === 418 || status === 999;
      }
    });

    // Handle responses based on status
    if (response.status === 999) {
      console.log('Processed non-standard 999 status:', response.data);
    } else {
      console.log('Standard success response:', response.data);
    }
  } catch (error) {
    console.error('Request failed due to an unhandled status or network error:', error.message);
  }
}

Global or Instance Configuration

If you are interacting with a service that consistently returns non-standard status codes, create a dedicated Axios instance:

import axios from 'axios';

const customApiClient = axios.create({
  baseURL: 'https://api.example.com',
  // Allow all status codes below 500 to resolve without throwing
  validateStatus: (status) => status < 500
});

export default customApiClient;

Method 2: Handling Non-Standard Codes with Interceptors

When non-standard status codes require centralized logic—such as parsing custom headers, logging, or transforming data before it reaches your calling code—use Axios response interceptors.

import axios from 'axios';

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

api.interceptors.response.use(
  (response) => {
    // Check for non-standard successful status codes
    if (response.status === 230) {
      console.info('Received custom status 230: Processing specific metadata.');
    }
    return response;
  },
  (error) => {
    // Check if the rejection was due to a non-standard error code
    if (error.response) {
      const { status, data } = error.response;

      if (status === 499) {
        console.warn('Client Closed Request (non-standard 499 detected).');
        return Promise.resolve({ data: null, status: 499, customHandled: true });
      }

      if (status >= 600) {
        console.error(`Received proprietary server status code: ${status}`);
      }
    }
    return Promise.reject(error);
  }
);

Best Practices

  1. Keep Rejection for True Failures: Avoid setting validateStatus: () => true unconditionally across entire applications, as this bypasses standard error handling and treats 500-level server crashes as successful responses.
  2. Explicit Code Matching: Specify explicit arrays or condition checks for the non-standard codes you anticipate (e.g., [200, 201, 204, 701].includes(status)).
  3. Inspect the response Object: When allowing non-standard codes through validateStatus, always evaluate response.status in your calling logic to branch operations appropriately.