softonic/axios-retry · error

ECONNABORTED

ECONNABORTED

Error message

ECONNABORTED

What it means

ECONNABORTED is set by axios when a request fails because its configured timeout elapsed, or the underlying socket/connection was aborted mid-flight (distinct from ECONNREFUSED/ECONNRESET which are refused/reset connections). At src/index.ts:96 axios-retry places 'ECONNABORTED' in CODE_EXCLUDE_LIST inside isNetworkError, so a timed-out request is deliberately NOT classified as a network error and the default retryCondition will not retry it. The inline comment at src/index.ts:103 ('Prevents retrying timed out & cancelled requests') documents this as intended behavior — a timeout is treated as a possibly-slow endpoint rather than a transient blip.

Source

Thrown at src/index.ts:116:96

  isNetworkError(error: AxiosError): boolean;
  isRetryableError(error: AxiosError): boolean;
  isSafeRequestError(error: AxiosError): boolean;
  isIdempotentRequestError(error: AxiosError): boolean;
  isNetworkOrIdempotentRequestError(error: AxiosError): boolean;
  exponentialDelay(retryCount?: number, error?: AxiosError, delayFactor?: number): number;
  linearDelay(delayFactor?: number): (retryCount: number, error: AxiosError | undefined) => number;
}

declare module 'axios' {
  export interface AxiosRequestConfig {
    'axios-retry'?: IAxiosRetryConfigExtended;
  }
}

export const namespace = 'axios-retry';

export function isNetworkError(error) {
  const CODE_EXCLUDE_LIST = ['ERR_CANCELED', 'ECONNABORTED'];
  if (error.response) {
    return false;
  }
  if (!error.code) {
    return false;
  }
  // Prevents retrying timed out & cancelled requests
  if (CODE_EXCLUDE_LIST.includes(error.code)) {
    return false;
  }
  // Prevents retrying unsafe errors
  return isRetryAllowed(error);
}

const SAFE_HTTP_METHODS = ['get', 'head', 'options'];
const IDEMPOTENT_HTTP_METHODS = SAFE_HTTP_METHODS.concat(['put', 'delete']);

export function isRetryableError(error: AxiosError): boolean {

View on GitHub (pinned to dd9b700dfb)

Solutions

  1. Raise the request timeout to comfortably exceed the endpoint's observed p99 latency (measure first, don't guess).
  2. Set shouldResetTimeout: true in the axios-retry options so each retry attempt gets a fresh full timeout budget instead of sharing the original.
  3. Provide a custom retryCondition that returns true for error.code === 'ECONNABORTED' on idempotent verbs if you specifically want timeouts retried.
  4. Investigate server-side latency or intermediary proxies/LBs if timeouts are chronic — retrying a genuinely slow endpoint just amplifies load.
  5. Check for a custom httpAgent/httpsAgent with its own timeout that is shorter than config.timeout.

Example fix

// before
axiosRetry(client, { retries: 3 }); // default: timeouts NOT retried
await client.get('/slow', { timeout: 2000 }); // -> ECONNABORTED, no retry

// after
axiosRetry(client, {
  retries: 3,
  shouldResetTimeout: true, // fresh budget per attempt
  retryCondition: (err) =>
    axiosRetry.isNetworkOrIdempotentRequestError(err) ||
    (err.code === 'ECONNABORTED' &&
      ['get', 'head', 'options', 'put', 'delete'].includes(
        err.config?.method ?? ''
      )),
});
await client.get('/slow', { timeout: 10000 });
Defensive patterns

Strategy: validation

Validate before calling

// Validate the timeout is sane relative to observed latency BEFORE sending.
function buildConfig(url, { timeout = 5000 } = {}) {
  const p99 = latencyP99MsFor(url); // your metrics source
  if (timeout <= p99) {
    console.warn(`timeout ${timeout}ms < p99 ${p99}ms for ${url}; raising`);
    timeout = Math.ceil(p99 * 2);
  }
  return { timeout };
}

Type guard

import type { AxiosError } from 'axios';

function isTimeoutError(error: unknown): error is AxiosError {
  return (
    typeof error === 'object' &&
    error !== null &&
    (error as AxiosError).code === 'ECONNABORTED' &&
    !(error as AxiosError).response
  );
}

Try / catch

try {
  await client.get('/slow', { timeout: 10000 });
} catch (err) {
  if (err?.code === 'ECONNABORTED') {
    // timeout — surface as a distinct, actionable error to the caller
    throw new Error(`Request timed out after ${err.config?.timeout}ms`);
  }
  throw err;
}

Prevention

When it happens

Trigger: A request whose AxiosRequestConfig.timeout (ms) is exceeded before the server responds, or whose socket is aborted, rejects with AxiosError code === 'ECONNABORTED' and no .response. The response interceptor calls isNetworkOrIdempotentRequestError -> isNetworkError, which returns false at src/index.ts:104 due to the CODE_EXCLUDE_LIST membership, so shouldRetry returns false and the error is rejected at src/index.ts:328 without any retry attempt.

Common situations: timeout config set lower than the endpoint's realistic p99 latency; high-latency or mobile networks; server-side processing (heavy query, cold start, large payload) exceeding the client timeout; a gateway/proxy/load-balancer with a shorter timeout than the client; shouldResetTimeout left at false (default) so cumulative retry delays eat the original timeout budget; recent axios 0.x -> 1.x upgrade where timeout semantics around proxies/agents changed.

Understand the failure class

Related errors


AI-assisted analysis of softonic/axios-retry@dd9b700dfb (2026-08-07). Data as JSON: /api/errors/74c052ba517dace6. Report an issue: GitHub.