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
ECONNREFUSED | Before 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 / ENETUNREACH | Before the target machine was even reached — routing failed. Wrong network, missing route, firewall dropping silently. |
ECONNRESET | Mid-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
131 analyzed errors across 77 libraries match this failure class. Each links to the thrown message, its source line, and documented fixes.
phpseclib/phpseclib
- Connection closed attempting to forward data to SSH agent
- Connection closed by server
- Connection closed by server; are you sure you're connected to an SSH server?
- Connection closed due to timeout
- Connection closed during signing
- +3 more in phpseclib
zeroclaw-labs/zeroclaw
- IRC connection closed by server
- QQ WebSocket connection closed: close_code={code}, reason="{reason}"
- QQ WebSocket connection closed: heartbeat ACK timeout ({MAX_MISSED_ACKS} consecutive missed ACKs)
- QQ WebSocket connection closed: internal message channel closed
- QQ WebSocket connection closed: invalid session (fresh auth required)
- +3 more in zeroclaw
php-amqplib/php-amqplib
- 0: Broken pipe or closed connection
- Broken pipe or closed connection
- Broken pipe or closed connection
- Broken pipe or closed connection
- Connection refused: %s
- +1 more in php-amqplib
redis/redis-py
- Connection closed by server.
- Connection closed by server.
- Connection closed by server.
- Connection closed by server.
- Connection closed by server.
CoplayDev/unity-mcp
- Connection closed before reading expected bytes
- Connection closed before receiving data
- Connection closed while reading
- Connection closed while reading
github/copilot-sdk
- Copilot request response used after RPC connection closed.
- Copilot request response used after RPC connection closed.
- LLM inference response used after RPC connection closed
- LLM inference response used after RPC connection closed.
hyperf/hyperf
astrid-runtime/astrid
- connection closed before {want_topic}
- daemon connection closed before command result
- daemon connection closed while waiting for the MCP broker for principal '{principal}'
microsoft/aspire
- Browser debug connection closed by the remote endpoint with status '{closeStatus}' ({(int)closeStatus}): {result.CloseStatusDescription}
- Connection closed
- connection closed
openai/openai-python
- WebSocket connection closed with unsent messages
- WebSocket connection closed with unsent messages
- WebSocket connection closed with unsent messages
…and 67 more libraries — search for your exact message.