Guides

Connection failures: ECONNREFUSED, ECONNRESET, and friends

A connection failure means TCP itself gave up — no HTTP status, no response body, nothing from the application on the other side. The error code tells you when in the connection's life it died, and that is the single most useful diagnostic fact.

The codes, by when they fire

ECONNREFUSEDBefore the connection existed. The target machine answered with a TCP RST: nothing is listening on that port. The host is reachable — the service isn't.
EHOSTUNREACH / ENETUNREACHBefore the target machine was even reached — routing failed. Wrong network, missing route, firewall dropping silently.
ECONNRESETMid-conversation. The peer (or a middlebox between you) sent RST on an established connection: process crash, forced restart, idle-timeout on a load balancer, or a proxy killing what it considers a dead connection.
EPIPE ("broken pipe")You wrote to a connection the peer had already closed. Same family as ECONNRESET, seen from the writing side.
"socket hang up"Node's wrapper for the server closing the connection before sending a complete response — usually a crashed handler or an aggressive keep-alive timeout.

Debugging in order

Work outward from the refused/reset distinction. For ECONNREFUSED: is the service running, and is it listening where you think?

ss -tlnp | grep 5432        # is anything listening on the port?
curl -v telnet://host:5432   # can this machine reach it?

The classic causes are the service binding 127.0.0.1 while you connect from another host (or another container), a container port that was never published, or connecting to localhost inside a container where "localhost" is the container itself.

For ECONNRESET mid-stream, suspect timeouts and middleboxes before code: idle keep-alive connections killed by a load balancer (AWS ALB defaults to 60s), a proxy with a shorter timeout than your client, or the peer process being restarted by a deploy or an OOM kill. Check the server's logs for the same timestamp — a reset with no server-side log line usually means a middlebox did it.

Handling it properly

Connection failures before any bytes are sent are safely retryable — with backoff and a retry budget, not a bare loop. Failures mid-request are only retryable if the request is idempotent. Pool users: retire a pooled connection on ECONNRESET/EPIPE instead of resurrecting it, and keep client keep-alive timeouts shorter than every hop in front of the server so the client, not a middlebox, decides when connections die.

Documented occurrences

11 analyzed errors across 6 libraries match this failure class. Each links to the thrown message, its source line, and documented fixes.

redis/redis-py

aio-libs/aiohttp

expressjs/express

sindresorhus/got

go-redis/redis

hyperium/hyper

Other failure classes