expressjs/express · warning · Error

ECONNABORTED

ECONNABORTED

Error message

Request aborted

What it means

Express's internal `sendfile` helper (lib/response.js:929-936) wraps the `send` file-streaming module for `res.sendFile()`/`res.download()`. When the underlying stream emits an abort — or finishes with an ECONNRESET (line 969 routes that to `onaborted`) — Express synthesizes `new Error('Request aborted')` with `code: 'ECONNABORTED'` and passes it to your sendFile callback (or to `next()` if none). It means the client disconnected before the file transfer completed; the server side did nothing wrong.

Source

Thrown at lib/response.js:933

    if (err) return req.next(err);
    self.send(str);
  };

  // render
  app.render(view, opts, done);
};

// pipe the send file stream
function sendfile(res, file, options, callback) {
  var done = false;
  var streaming;

  // request aborted
  function onaborted() {
    if (done) return;
    done = true;

    var err = new Error('Request aborted');
    err.code = 'ECONNABORTED';
    callback(err);
  }

  // directory
  function ondirectory() {
    if (done) return;
    done = true;

    var err = new Error('EISDIR, read');
    err.code = 'EISDIR';
    callback(err);
  }

  // errors
  function onerror(err) {
    if (done) return;
    done = true;

View on GitHub ↗ (pinned to a3714473fe)

Solutions

  1. Handle it in the sendFile/download callback: if (err && err.code === 'ECONNABORTED') just log at debug level and return — the client is gone, do not attempt another response.
  2. In global error middleware, check `err.code === 'ECONNABORTED'` (and `res.headersSent`) and swallow/log instead of rendering a 500.
  3. If aborts are frequent and unwanted, raise proxy/load-balancer timeouts (e.g. nginx `proxy_read_timeout`, ALB idle timeout) above your largest transfer time.
  4. For very large files, serve via a static file server/CDN or `express.static` with range support so retries are cheap.

Example fix

// before
res.download('/data/report.zip', function (err) {
  if (err) next(err); // turns every client cancel into a 500 in logs
});

// after
res.download('/data/report.zip', function (err) {
  if (err) {
    if (err.code === 'ECONNABORTED') {
      debug('client aborted download');
      return; // client disconnected — nothing to send
    }
    return next(err);
  }
});
Defensive patterns

Strategy: try-catch

Type guard

function isConnAborted(err) {
  return err != null && typeof err === 'object' && err.code === 'ECONNABORTED';
}

Try / catch

res.sendFile(filePath, function (err) {
  if (err) {
    if (err.code === 'ECONNABORTED') {
      // Client disconnected mid-transfer; nothing to send. Log and stop.
      console.warn('client aborted download of %s', filePath);
      return;
    }
    next(err);
  }
});

Prevention

When it happens

Trigger: Calling `res.sendFile(path, cb)` or `res.download(path, cb)` while the client closes the socket mid-transfer: the user hits stop/navigates away, an HTTP client times out or calls `request.abort()`, a proxy (nginx, ELB) kills the upstream connection, or a video/PDF viewer issues range requests and drops earlier ones. It is delivered via the callback, or hits your error middleware if you passed none.

Common situations: Log noise from users cancelling large downloads or streaming video with range requests; load balancers with idle timeouts shorter than the file transfer time; frontend fetch calls with AbortController timeouts; health checkers/scanners that disconnect immediately. Developers often mistake it for a server bug and crash the process by re-throwing it, or double-respond by treating it as a case needing an error page.

Related errors


AI-assisted analysis of expressjs/express@a3714473fe (2026-07-31). Data as JSON: /data/errors/265a834aab0d9a54.json. Report an issue: GitHub ↗.