Error reference Libraries

Fix Node.js ECONNRESET errors

Error: read ECONNRESET means the connection was alive — then the other end, or a middlebox in between, tore it down with a TCP reset mid-conversation. Unlike ECONNREFUSED, you did connect. The usual suspects are keep-alive timeout races, overloaded servers, NAT and firewall idle cut-offs, and, in scraping setups, proxy rotation or target-side defenses closing connections deliberately.

Node.js ECONNRESET

What ECONNRESET means

ECONNRESET surfaces when the peer sends a TCP RST on an established connection: the socket was open, data may already have flowed, and then it was killed abruptly instead of closed with a normal FIN handshake. In Node it appears on reads (read ECONNRESET) or writes (write ECONNRESET, often alongside EPIPE) — and if it fires on a socket with no 'error' listener, it crashes the entire process.

The single most common mechanical cause is the keep-alive race: your HTTP agent reuses a pooled connection at the same moment the server's idle timeout closes it. The server's close and your new request cross on the wire, and the request dies with a reset. It is inherently timing-dependent, which is why ECONNRESET is intermittent and hard to reproduce on demand.

Beyond that race, resets come from crashed or restarting processes, load balancers culling idle or long-lived connections, NAT devices dropping mappings during quiet periods, and servers that reset connections deliberately — which is exactly what rate limiters and anti-bot systems do when they dislike a traffic pattern.

Node.js ECONNRESET

Step-by-step fixes for ECONNRESET

Because resets are timing-dependent, make your client resilient first, then remove the specific cause. Work through these in order.

  1. Add retry with backoff for idempotent requests (GET, HEAD). A reset on a reused keep-alive connection is routine; one retry on a fresh connection usually succeeds.
  2. Handle the error: attach 'error' listeners to sockets and streams, or wrap awaited calls in try/catch, so a single reset cannot crash the process.
  3. Fix the keep-alive race: set your client's idle socket timeout below the server's (for undici, lower keepAliveTimeout; for http.Agent, tune keepAlive and timeout). As a diagnostic, disable keep-alive entirely — if resets vanish, the race was your cause.
  4. Reduce concurrency. Hundreds of simultaneous sockets to one host trip per-IP connection caps on load balancers and firewalls, which shed load by resetting.
  5. Keep data moving on long transfers: NAT and stateful firewalls drop mappings on idle flows. Stream steadily, enable TCP keep-alive probes, and avoid long processing pauses mid-download.
  6. On rotating proxies, check whether resets correlate with rotation timing — a connection that outlives its exit IP gets cut. Use a sticky session for anything long-lived.
  7. Watch for a pattern: resets that begin after N successful requests from one IP are a target-side defense, not a network fault. Slow down, spread traffic across more IPs, and add pacing jitter.
  8. Update Node and undici — several past versions carried keep-alive pooling bugs that produced spurious ECONNRESET under load.
Node.js ECONNRESET

ECONNRESET with rotating proxies: connection lifetime vs rotation

Residential proxies add two reset sources of their own. First, rotation: if your plan rotates the exit IP on an interval and a connection outlives that interval, the transfer is cut mid-stream — a setup mistake, not a flaky network. ProxyOmega Budget Unlimited rotates per port on an interval, so long downloads, streamed responses, and websockets belong on a sticky session: append -session-<id> to your username to hold one exit for up to 24 hours, or -ttl-<seconds> to set the exact lifetime you need.

Second, the physics of residential networks: exits are real household devices, and a small fraction of connections will drop as devices go offline. That is why retry logic is non-negotiable on any residential pool, at any price tier. ProxyOmega's network holds a 99.7% success rate — the remaining fraction is precisely what your retry-with-backoff exists to absorb.

Sticky sessions for long-lived connections

Anything that must survive minutes — large file downloads, paginated crawls sharing one login state, websockets — should pin its exit. -session-<id> keeps the same IP across requests for up to 24 hours, and -ttl-<seconds> gives you explicit lifetime control. Rotate between logical jobs, not inside them.

Retries sized for residential reality

Treat a reset as a signal to reconnect, not an outage. Retry idempotent requests two or three times with short backoff, cap concurrency per target host, and log reset rates per exit country — a localized spike usually points at one region or one target defense, not your code.

When the target is doing the resetting

Resets that appear after bursts of traffic from a single IP are deliberate. Spread load across session IDs and countries, add pacing jitter, and match IP quality to target strictness: ProxyOmega Platinum offers Tier-1 ISP-quality residential IPs and Mobile offers real 4G/5G carrier IPs — both draw far less friction from strict targets than datacenter ranges.

Node.js ECONNRESET

A reset-resilient request through a sticky session

This example pins one exit IP with a session ID so rotation cannot cut the transfer, and retries on a reset with backoff. The same pattern applies to any HTTP client: a sticky exit for the duration of the job, plus a small retry budget for the residual churn.

# Sticky session: -session-<id> holds one exit IP (up to 24h) so
# rotation cannot reset a long transfer mid-stream.
node -e '
const { fetch, ProxyAgent } = require("undici");
const proxy = new ProxyAgent(
  "http://USERNAME-session-job42:[email protected]:10000");

async function get(url, tries = 3) {
  for (let i = 1; i <= tries; i++) {
    try {
      const res = await fetch(url, { dispatcher: proxy });
      return await res.text();
    } catch (err) {
      const code = err.cause && err.cause.code;
      if (i === tries || code !== "ECONNRESET") throw err;
      await new Promise((s) => setTimeout(s, 500 * i)); // backoff
    }
  }
}
get("https://api.ipify.org").then(console.log);
'
FAQ

Frequently asked questions

Is ECONNRESET my fault or the server's?
Either side can send a reset, and middleboxes in between — NAT, firewalls, load balancers — count too. The pattern tells you: resets on reused connections after idle periods are keep-alive races; resets under high concurrency are connection caps; resets after N requests from one IP are deliberate rate limiting. Rare random resets on residential networks are normal churn — absorb them with retries.
Why does one ECONNRESET crash my whole Node process?
An 'error' event on a socket or stream with no listener is thrown as an uncaught exception, and Node terminates by default. Attach error handlers to every socket and stream you create, wrap awaited requests in try/catch, and treat a process-level uncaughtException handler as a last-resort logger rather than a fix — it cannot restore the failed request.
Can proxy rotation cause ECONNRESET?
Yes, when a connection outlives its exit IP. Interval rotation is ideal for spreading many short requests across the pool, but a download or websocket that spans a rotation boundary gets cut mid-stream. On ProxyOmega, append -session-<id> to your username to hold one exit for up to 24 hours, or -ttl-<seconds> to set the lifetime explicitly.
How many retries should a scraper use for ECONNRESET?
Two or three attempts with exponential backoff covers transient resets without hammering a struggling target. Retry only idempotent methods automatically, use a fresh connection per attempt, and record which exits and targets reset most. If retries routinely exhaust, the cause is systematic — a keep-alive mismatch, a connection cap, or a target defense — and needs a configuration fix, not more retries.

Stop losing transfers to dropped connections. Start routing today.

Sticky sessions up to 24h, per-port rotation control, and a 99.7% success rate across a 90M+ IP network.

ProxyOmega ProxyOmega

90M+ ethically-sourced IPs across 200+ countries and 30,000+ cities. Residential, mobile, ISP and IPv6 proxies for scraping and AI agents.

GDPRCCPA
Product
Premium Unlimited Budget Unlimited Residential / ISP Mobile IPv6 Chrome Extension
Solutions
Web scraping AI agents Price monitoring SERP & SEO Integrations All use cases
Resources
Glossary Error codes Free tools Proxies by platform Locations
Company
About Blog Docs Reseller program Affiliate Contact Sign in
© 2026 ProxyOmega Ltd. All rights reserved.