sindresorhus/got · error · ReadError

ECONNRESET

ECONNRESET

Error message

The server aborted pending request

What it means

Produced at source/core/index.ts:1111 in the `response.once('aborted', ...)` handler. When the underlying IncomingMessage emits `aborted` (the server closed the connection before sending a complete response) and there is no Content-Length mismatch to report instead, got wraps the event in a ReadError with code ECONNRESET. The guard at line 1103 first allows close-delimited responses (no Content-Length) whose nativeResponse.complete is true, because in that case the close was the intended EOF, not an abort.

Source

Thrown at source/core/index.ts:1111

			this._aborted = true;

			this._beforeError(new ReadError(error, this));
		});

		response.once('aborted', () => {
			// Without Content-Length, connection close is the intended EOF signal (RFC 9110 §8.6),
			// not a premature abort. For wrapped decompression streams, rely on the native
			// response completion state because the wrapper strips `content-length`.
			if (this._responseSize === undefined && nativeResponse.complete) {
				return;
			}

			this._aborted = true;

			// Check if there's a content-length mismatch to provide a more specific error
			if (!this._checkContentLengthMismatch()) {
				this._beforeError(new ReadError({
					name: 'Error',
					message: 'The server aborted pending request',
					code: 'ECONNRESET',
				}, this));
			}
		});

		let canFinalizeResponse = false;
		const handleResponseEnd = () => {
			if (
				!canFinalizeResponse
				|| !response.readableEnded
			) {
				return;
			}

			canFinalizeResponse = false;

View on GitHub (pinned to e3924aa1e5)

Solutions

  1. Enable retry on ECONNRESET (got does this by default) and increase retry.limit if the upstream is known to be flaky.
  2. Lower `timeout.request` so the client gives up before the server's idle-drop, or raise the upstream/proxy timeout to exceed your longest response.
  3. Switch to HTTP/2 (`http2: true`) which multiplexes and recovers more gracefully from connection issues.

Example fix

// before
await got('https://flaky-api/large', { timeout: { request: 60000 } });

// after — retry reset connections, keep timeouts realistic
await got('https://flaky-api/large', {
  timeout: { request: 30000 },
  retry: { limit: 4, errorCodes: ['ECONNRESET', 'ETIMEDOUT', 'EPIPE'] }
});
Defensive patterns

Strategy: retry

Validate before calling

// Configure retry to cover connection resets during response.
const options = {
  retry: {
    limit: 4,
    errorCodes: ['ECONNRESET', 'ETIMEDOUT', 'ECONNREFUSED', 'EPIPE']
  },
  timeout: { request: 30000 }
};

Try / catch

import {RequestError} from 'got';

try {
  await got(url, options);
} catch (error) {
  if (error instanceof RequestError && error.code === 'ECONNRESET' && /server aborted pending request/.test(error.message)) {
    // got already retried up to retry.limit; surface as a transient upstream issue
    throw new Error('Upstream closed the connection mid-response after retries', { cause: error });
  }
  throw error;
}

Prevention

When it happens

Trigger: Server closes the TCP connection before finishing the response body; upstream gateway timeout that drops the socket mid-stream; server crashed mid-response; reverse proxy recycled the worker; client-side socket was forcibly reset by a NAT or firewall after a long idle gap during a slow response.

Common situations: Long-running downloads behind an aggressive proxy timeout, upstream service instability, deployments that restart servers mid-request, mobile/flaky networks that reset connections, or load balancers that drop connections after a fixed byte quota.

Related errors


AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03). Data as JSON: /data/errors/a68585bb22d234fa.json. Report an issue: GitHub.