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.

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.

Understand the failure class

Related errors


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

Appendix: 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)