coderain blog

How to Properly Cancel Axios Requests in Request Interceptors When No Token Exists: Fixing 'cancelToken' Undefined Error

In modern web applications, handling authentication tokens (e.g., JWT) is critical for securing API requests. A common requirement is to cancel requests when no valid token exists (e.g., user not logged in, token expired, or token missing from storage). This prevents unauthorized requests from reaching the server, reduces unnecessary network traffic, and avoids 401/403 errors that clutter logs.

However, developers often encounter the frustrating 'cancelToken' undefined error when implementing this logic with Axios interceptors. This error typically arises from incorrect initialization or usage of Axios cancel mechanisms.

In this blog, we’ll demystify how to properly cancel Axios requests in request interceptors when no token exists, step-by-step. We’ll also fix the 'cancelToken' undefined error and explore best practices to ensure robust request cancellation.

2026-01

Table of Contents#

  1. Understanding the Problem: Why Cancel Requests Without Tokens?
  2. Axios Interceptors: A Quick Refresher
  3. Cancel Tokens in Axios: Old vs. New Approaches
  4. Step-by-Step Solution: Canceling Requests in Interceptors
  5. Fixing the 'cancelToken' Undefined Error
  6. Testing Your Implementation
  7. Best Practices for Request Cancellation
  8. Conclusion
  9. References

Understanding the Problem: Why Cancel Requests Without Tokens?#

Before diving into the solution, let’s clarify why canceling requests without tokens matters:

  • Security: Prevents sensitive endpoints from receiving unauthenticated requests.
  • Performance: Reduces unnecessary server load and network traffic.
  • User Experience: Avoids misleading 401/403 errors that may confuse users (e.g., "Login required" is clearer than a generic error).
  • Clean Code: Centralizes token validation logic in interceptors, avoiding redundant checks in every request.

The most common pitfall here is the 'cancelToken' undefined error. This occurs when Axios tries to use a cancel token that hasn’t been properly initialized, often due to incorrect usage of Axios’ cancellation APIs.

Axios Interceptors: A Quick Refresher#

Axios interceptors let you "intercept" requests or responses before they are handled by then/catch. For our use case, request interceptors are ideal: they run before a request is sent, allowing us to check for a token and cancel the request if needed.

A basic request interceptor looks like this:

import axios from 'axios';
 
const api = axios.create({
  baseURL: 'https://api.example.com'
});
 
// Request interceptor
api.interceptors.request.use(
  (config) => {
    // Modify config before request is sent (e.g., add headers, check tokens)
    return config;
  },
  (error) => {
    // Handle request error
    return Promise.reject(error);
  }
);

We’ll use this interceptor to check for a valid token. If none exists, we’ll cancel the request here.

Cancel Tokens in Axios: Old vs. New Approaches#

Axios supports two methods for canceling requests:

1. CancelToken (Legacy, Deprecated)#

Historically, Axios used CancelToken (inspired by Bluebird’s cancellation API). However, CancelToken is deprecated in Axios v0.22.0+ in favor of the standard AbortController (see below).

Example with CancelToken:

import axios, { CancelToken } from 'axios';
 
const source = CancelToken.source();
 
api.get('/data', {
  cancelToken: source.token
});
 
// Cancel the request later
source.cancel('Request canceled due to missing token');

The modern, standardized approach is to use the Web API AbortController, which is supported by most browsers and aligns with fetch API conventions.

Example with AbortController:

const controller = new AbortController();
 
api.get('/data', {
  signal: controller.signal
});
 
// Cancel the request later
controller.abort('Request canceled due to missing token');

Since CancelToken is deprecated, we’ll focus on AbortController for the solution. However, we’ll also address the 'cancelToken' undefined error for legacy implementations.

Step-by-Step Solution: Canceling Requests in Interceptors#

Let’s walk through implementing request cancellation when no token exists, using AbortController (recommended) and fixing common errors.

Step 1: Define a Token Retrieval Function#

First, create a helper to fetch the token from storage (e.g., localStorage, sessionStorage, or cookies). Adjust this based on where your app stores tokens:

// utils/auth.js
export const getAuthToken = () => {
  // Example: Retrieve token from localStorage
  return localStorage.getItem('authToken');
};

Step 2: Create an Axios Instance with Interceptor#

Create a dedicated Axios instance (to avoid polluting global Axios) and add a request interceptor. Inside the interceptor:

  • Check if a token exists using getAuthToken().
  • If no token, cancel the request with AbortController.
  • If a token exists, add it to the request headers (optional but common).

Full Implementation with AbortController:#

// api/client.js
import axios from 'axios';
import { getAuthToken } from '../utils/auth';
 
const api = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000
});
 
// Request interceptor to check for token and cancel if missing
api.interceptors.request.use(
  (config) => {
    const token = getAuthToken();
 
    if (!token) {
      // No token: Cancel the request using AbortController
      const controller = new AbortController();
      // Attach the abort signal to the request config
      config.signal = controller.signal;
      // Abort immediately with a reason
      controller.abort('Request canceled: No authentication token found');
    } else {
      // Token exists: Add it to headers (optional)
      config.headers.Authorization = `Bearer ${token}`;
    }
 
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);
 
export default api;

How It Works#

  • No Token: We create an AbortController, attach its signal to the request config, and immediately call controller.abort(). This cancels the request before it’s sent.
  • With Token: The request proceeds with the token in the Authorization header.

Handling Cancelled Requests in Components#

When a request is aborted, Axios rejects the promise with an AbortError. Catch this in your components to handle cancellation gracefully (e.g., redirect to login):

// components/DataFetcher.js
import api from '../api/client';
 
const fetchData = async () => {
  try {
    const response = await api.get('/protected-data');
    return response.data;
  } catch (error) {
    if (error.name === 'AbortError') {
      // Handle cancellation (e.g., redirect to login)
      console.log('Request cancelled:', error.message);
      window.location.href = '/login';
    } else {
      // Handle other errors (e.g., network issues, 401)
      console.error('Request failed:', error);
    }
  }
};

Fixing the 'cancelToken' Undefined Error#

The 'cancelToken' undefined error typically occurs in two scenarios:

Scenario 1: Using Deprecated CancelToken Without Initialization#

If you’re using the legacy CancelToken approach and forget to initialize the cancel source, source.token will be undefined.

Common Mistake:

// ❌ Incorrect: source is not initialized
api.interceptors.request.use((config) => {
  const token = getAuthToken();
  if (!token) {
    config.cancelToken = source.token; // source is undefined!
    source.cancel('No token');
  }
  return config;
});

Fix for CancelToken:
Always initialize CancelToken.source() before using it:

// ✅ Correct: Initialize source first
import { CancelToken } from 'axios';
 
api.interceptors.request.use((config) => {
  const token = getAuthToken();
  if (!token) {
    const source = CancelToken.source(); // Initialize source
    config.cancelToken = source.token; // Now source.token is defined
    source.cancel('Request canceled: No token');
  }
  return config;
});

Scenario 2: Mixing cancelToken and signal#

If you’re using AbortController (which uses signal) but accidentally reference cancelToken in the config, Axios will throw 'cancelToken' undefined if cancelToken isn’t set.

Common Mistake:

// ❌ Incorrect: Using cancelToken with AbortController
const controller = new AbortController();
config.cancelToken = controller.signal; // Should be config.signal!

Fix for AbortController:
Use signal (not cancelToken) with AbortController:

// ✅ Correct: Use config.signal
const controller = new AbortController();
config.signal = controller.signal; // Attach signal to config
controller.abort('No token');

Testing the Implementation#

To verify your setup:

  1. Clear the Token: Delete the token from localStorage (or your storage method) to simulate a logged-out user.
  2. Trigger a Request: Call an API endpoint using your api instance (e.g., fetchData()).
  3. Check DevTools: In Chrome DevTools > Network tab, the request should show as "cancelled" (status: "(failed) net::ERR_ABORTED").
  4. Catch the Error: Ensure your component’s catch block logs the AbortError and redirects to login.

Best Practices#

  1. Use AbortController Over CancelToken:
    CancelToken is deprecated, so adopt AbortController for future-proof code.

  2. Centralize Token Logic:
    Keep token retrieval (e.g., getAuthToken()) in a utility function to avoid duplication.

  3. Handle Token Expiry Separately:
    This solution cancels requests when no token exists. For expired tokens, use a response interceptor to refresh the token instead of canceling.

  4. Avoid Silent Failures:
    Always catch AbortError in components to inform users (e.g., "Please log in to continue").

  5. Clean Up Abort Controllers:
    For long-running requests (e.g., polling), store controllers in a list and abort them when components unmount to prevent memory leaks.

Conclusion#

Canceling Axios requests in interceptors when no token exists is critical for security and performance. By using AbortController (Axios’ recommended approach) and properly initializing cancellation signals, you can avoid the 'cancelToken' undefined error.

Key takeaways:

  • Use AbortController for modern, standardized cancellation.
  • Always initialize cancellation sources/signals before using them.
  • Handle AbortError in components to guide users (e.g., redirect to login).

With this setup, your app will gracefully handle missing tokens and avoid unnecessary server requests.

References#