How to fix Error: Cancelled (operation cancelled by user or timeout) in Node.js

Node.jsINTERMEDIATELOWUpdated Dec 9, 2025ยท 350 views

This error occurs when an asynchronous operation in Node.js is deliberately cancelled using AbortController or times out. It indicates that the operation was terminated before completion, either programmatically or due to exceeding a time limit.

Quick fix

Fixes AbortError

try {
  const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
  const data = await response.json();
} catch (error) {
  if (error.name === 'AbortError' || error.name === 'TimeoutError') {
    console.log('Request was cancelled or timed out');
    // Handle gracefully - this is expected behavior
    return;
  }
  // Only throw unexpected errors
  throw error;
}
  1. Check if error is an intentional cancellation
  2. Increase timeout duration if operations are timing out
  3. Properly clean up AbortController listeners
  4. Check signal status before starting operations
node.js โ€” error
try {
const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
const data = await response.json();
} catch (error) {
if (error.name === 'AbortError' || error.name === 'TimeoutError') {
console.log('Request was cancelled or timed out');
// Handle gracefully - this is expected behavior
return;
}
// Only throw unexpected errors
throw error;
}
Error: Cancelled (operation cancelled by user or timeout)

What this error means

The "Cancelled" error in Node.js typically manifests as an AbortError DOMException when an operation is cancelled using the AbortController API. This is a controlled cancellation mechanism that allows developers to abort ongoing asynchronous operations like HTTP requests, file system operations, or long-running processes. When an AbortSignal is triggered (via `abort()` or `AbortSignal.timeout()`), any operation listening to that signal will immediately stop execution and reject its promise with an AbortError. This is not a bug but an intentional design pattern for managing the lifecycle of asynchronous operations. The error message "Cancelled (operation cancelled by user or timeout)" indicates that the operation was explicitly terminated rather than failing due to network issues, invalid data, or other runtime errors. This distinction is important for error handling logic.

Typical symptoms

  • Promise rejections with "AbortError" or "Cancelled" error type
  • fetch() requests fail immediately when signal is aborted
  • Operations stop mid-execution without completing their task
  • Error occurs precisely when timeout duration is reached
  • Multiple concurrent operations fail simultaneously when sharing an AbortController
  • Unhandled error events in POST requests with request bodies when cancelled

Common causes

  1. User explicitly calls abort() on an AbortController to cancel an operation
  2. Operation exceeds time limit set by AbortSignal.timeout()
  3. Shared AbortController is aborted, affecting multiple operations
  4. Already-aborted signal is passed to a new operation that immediately throws
  5. Network request takes longer than the configured timeout threshold
  6. Application logic cancels operations when user navigates away or changes actions
  7. Resource cleanup triggers abortion of pending operations during shutdown

How to fix "Error: Cancelled (operation cancelled by user or timeout)"

1Check if error is an intentional cancellation

First, determine whether this is an expected AbortError that should be handled gracefully:

javascript
try {
  const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
  const data = await response.json();
} catch (error) {
  if (error.name === 'AbortError' || error.name === 'TimeoutError') {
    console.log('Request was cancelled or timed out');
    // Handle gracefully - this is expected behavior
    return;
  }
  // Only throw unexpected errors
  throw error;
}

Check the error name to distinguish cancellations from genuine failures.

2Increase timeout duration if operations are timing out

If legitimate operations are being cancelled due to insufficient timeout values, adjust the duration:

javascript
// Before: Too short for slow APIs
const signal = AbortSignal.timeout(1000); // 1 second

// After: More realistic timeout
const signal = AbortSignal.timeout(10000); // 10 seconds

const response = await fetch(apiUrl, { signal });

Monitor your operations to determine appropriate timeout values based on typical response times.

3Properly clean up AbortController listeners

Remove event listeners after operations complete to prevent memory leaks:

javascript
const controller = new AbortController();
const signal = controller.signal;

const abortHandler = () => {
  console.log('Operation aborted');
};

signal.addEventListener('abort', abortHandler);

try {
  await someAsyncOperation(signal);
} finally {
  // Always remove listener when done
  signal.removeEventListener('abort', abortHandler);
}

This prevents issues with long-lived AbortController instances.

4Check signal status before starting operations

Prevent unnecessary work by checking if the signal is already aborted:

javascript
async function performTask(signal) {
  // Check immediately before starting
  if (signal.aborted) {
    throw new DOMException('Operation already cancelled', 'AbortError');
  }

  // Proceed with the operation
  const result = await expensiveOperation();

  // Check periodically during long operations
  if (signal.aborted) {
    throw new DOMException('Operation cancelled mid-execution', 'AbortError');
  }

  return result;
}

This avoids starting work that will immediately be cancelled.

5Handle POST request cancellations properly

When cancelling POST requests with bodies, handle potential unhandled error events:

javascript
const controller = new AbortController();

try {
  const response = await fetch(url, {
    method: 'POST',
    body: JSON.stringify(data),
    signal: controller.signal,
    headers: { 'Content-Type': 'application/json' }
  });

  return await response.json();
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('POST request cancelled');
    return null; // or appropriate default
  }
  throw error;
}

Always wrap cancellable POST requests in try-catch blocks to handle abort errors gracefully.

6Implement retry logic for timeout scenarios

Add exponential backoff for operations that may legitimately need more time:

javascript
async function fetchWithRetry(url, maxRetries = 3) {
  let lastError;

  for (let i = 0; i < maxRetries; i++) {
    try {
      const timeout = 5000 * Math.pow(2, i); // Exponential: 5s, 10s, 20s
      const signal = AbortSignal.timeout(timeout);
      const response = await fetch(url, { signal });
      return await response.json();
    } catch (error) {
      if (error.name === 'TimeoutError' && i < maxRetries - 1) {
        console.log(`Attempt ${i + 1} timed out, retrying...`);
        lastError = error;
        continue;
      }
      throw error;
    }
  }

  throw lastError;
}

This handles transient network issues that cause timeouts.

Advanced notes

AbortController with Multiple Operations

You can use a single AbortController to cancel multiple related operations simultaneously:

javascript
const controller = new AbortController();
const signal = controller.signal;

const promises = [
  fetch('/api/users', { signal }),
  fetch('/api/posts', { signal }),
  fetch('/api/comments', { signal })
];

// Cancel all three requests at once
setTimeout(() => controller.abort(), 3000);

try {
  const results = await Promise.all(promises);
} catch (error) {
  // All three will fail with AbortError
}

Node.js Core API Support

The AbortController API is supported across many Node.js core modules: fs, net, http, events, child_process, readline, and stream. You can use the same cancellation pattern consistently:

javascript
const { readFile } = require('fs/promises');

const controller = new AbortController();
setTimeout(() => controller.abort(), 100);

try {
  const data = await readFile('/large-file.txt', {
    signal: controller.signal
  });
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('File read cancelled');
  }
}

Custom Cancellable Operations

You can make your own functions respect AbortSignals:

javascript
async function customOperation(signal) {
  return new Promise((resolve, reject) => {
    if (signal.aborted) {
      return reject(new DOMException('Aborted', 'AbortError'));
    }

    const abortHandler = () => {
      cleanup();
      reject(new DOMException('Aborted', 'AbortError'));
    };

    signal.addEventListener('abort', abortHandler);

    // Your async work here...

    function cleanup() {
      signal.removeEventListener('abort', abortHandler);
    }
  });
}

Distinguishing User Aborts from Timeouts

Node.js 17.3.0+ allows differentiation:

javascript
catch (error) {
  if (error.name === 'TimeoutError') {
    // Automatic timeout
  } else if (error.name === 'AbortError') {
    // Manual abort() call
  }
}

This helps provide more specific user feedback about why an operation was cancelled.

Frequently asked questions

What does "AbortError" mean?
js typically manifests as an AbortError DOMException when an operation is cancelled using the AbortController API. This is a controlled cancellation mechanism that allows developers to abort ongoing asynchronous operations like HTTP requests, file system operations, or long-running processes. timeout()), any operation listening to that signal will immediately stop execution and reject its promise with an AbortError.
How do I fix "AbortError"?
This error occurs when an asynchronous operation in Node.js is deliberately cancelled using AbortController or times out. It indicates that the operation was terminated before completion, either programmatically or due to exceeding a time limit.
What causes "AbortError"?
User explicitly calls abort() on an AbortController to cancel an operation Operation exceeds time limit set by AbortSignal.timeout() Shared AbortController is aborted, affecting multiple operations
Is the "AbortError" error serious?
It is a low-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading