The API isn't responding: timeout, connection reset, or a block?
Short answer: an API request passes through four layers: DNS finds the server's address, TCP opens a connection, TLS agrees on encryption, and HTTP carries the request and the response. "The API isn't responding" means the request died at one of them, and the error text tells you which. A timeout and a reset are different things. With a timeout nothing came back at all. Connection reset by peer means the other side cut the connection: the server, a proxy in front of it, or a box along the way.
Read the error first#
The error text usually names the layer. The same problem sounds different in different tools:
| What the tool says | Layer | What it means |
|---|---|---|
Could not resolve host (curl, code 6), ENOTFOUND (Node.js), no such host (Go), Name or service not known (Python on Linux) | DNS | The server's address wasn't found |
Connection refused (curl, code 7), ECONNREFUSED | TCP | The server is reachable, but nothing listens on that port, or a firewall refused outright |
Connection timed out after … milliseconds (curl, code 28), ETIMEDOUT, i/o timeout | TCP | Packets go nowhere: a wrong address, a firewall silently dropping them, or a broken route |
Connection reset by peer (curl, code 35 during TLS, 56 later), ECONNRESET | TCP or TLS | Something sent a reset: the server crashed, or a proxy or a box along the way cut in |
SSL certificate problem (curl, code 60) | TLS | Certificate verification failed |
Operation timed out … with 0 bytes received (curl, code 28) | HTTP | The connection is up, but the server didn't answer in time |
502, 503, 504 | HTTP | A proxy or load balancer answered; the service behind it didn't |
curl's code is in $? right after the command: curl https://api.example.com; echo $?.
The timeout lines in the table appear when you set --connect-timeout or --max-time. Without them curl waits until the OS gives up, a minute or two, and says Failed to connect to … after 75003 ms: Could not connect to server; the code can be 28 or 7 depending on the version. So run the first check with timeouts.
What does the client say?
- What happened
- Someone sent a connection reset: the server, a load balancer, or a box on the path. No HTTP response.
- How it fails
- At once. Most often right after Client hello, so during the TLS handshake (code 35). Later it's code 56.
- Where to look
- A restarting server, a proxy, limits. If it works from another network, something on the path interferes.
- Check
openssl s_client -connect api.example.com:443 -servername api.example.com- In Tetiva
request failed: Get "https://api.example.com/health": read tcp 192.0.2.15:52876->203.0.113.10:443: read: connection reset by peer
What connection reset by peer means#
Connection reset by peer means the other end of the connection sent a TCP RST packet and tore the connection down. To your program, "the other end" is whoever answers for the server: the server itself, a load balancer or proxy in front of it, or a firewall on the path. No HTTP response comes back at all.
The same error in different languages and tools:
- Python on Linux:
ConnectionResetError: [Errno 104] Connection reset by peer,[Errno 54]on macOS. requests wraps it asConnectionError: ('Connection aborted.', ConnectionResetError(104, ...)). - Windows:
[WinError 10054] An existing connection was forcibly closed by the remote host, orsocket error 10054in older tools. - Node.js:
Error: read ECONNRESET, orsocket hang upwith the codeECONNRESET. - Java:
java.net.SocketException: Connection reset. - Go:
read tcp …: read: connection reset by peer. - curl:
Recv failure: Connection reset by peer, exit code 56. If the reset arrives during the TLS handshake, the code is 35 and the verbose output showsOpenSSL SSL_connect: Connection reset by peer. - SSH:
kex_exchange_identification: read: Connection reset by peer. The check is the same on port 22:nc -vz host 22. If the port is open and SSH still resets, the server'sMaxStartupslimit is the usual cause: too many unauthenticated connections, often from scanners. A fail2ban ban looks different, asConnection refused.
If the reset comes right after Client hello, go to step 3, TLS.
When the reset is intermittent
If resets happen now and then and a retry works, the client most likely sent the request on a connection the server had already closed for being idle. HTTP clients keep connections open (keep-alive) and reuse them, while the server closes idle ones sooner: a Node.js server's keepAliveTimeout defaults to 5 seconds. Keep the client pool's idle timeout below the server's and retry idempotent requests (GET, PUT, DELETE) once. Another common cause is a server restarting during a deploy and dropping open connections.
Walk the layers top to bottom#
Start with curl -v and a short timeout. The line where the output stops tells you how far the request got:
curl -v --connect-timeout 5 --max-time 20 https://api.example.com/health
nc -vz -w 5 api.example.com 443and the same request from another network1. DNS: was the address found?
If instead of Host api.example.com:443 was resolved curl says Could not resolve host straight away, it's DNS. Compare what different resolvers say:
dig +short api.example.com
dig +short api.example.com @1.1.1.1
dig +short api.example.com @8.8.8.8
If the answers differ, or one resolver doesn't know the name, the problem is DNS, not the API. To test the server while bypassing DNS, pin the address by hand: curl --resolve api.example.com:443:203.0.113.10 https://api.example.com/health.
On some corporate networks and in some countries, queries to public resolvers such as 8.8.8.8 are intercepted, or encrypted DNS is blocked altogether. If your code or server pins an external resolver, check that first.
2. TCP: connection refused or connection timed out
When the connection opens, TLS starts right after Trying 203.0.113.10:443...: you'll see ALPN and Client hello. If you don't:
Connection refusedcame back at once: the server is there, but the port is closed. Check the port in the URL and that the service is running.- A pause, then
Connection timed out: packets aren't getting through. A wrong address, a firewall, or a routing problem.
To test the port without HTTP, run nc -vz api.example.com 443, or Test-NetConnection api.example.com -Port 443 on Windows. If the server has both IPv4 and IPv6, compare curl -4 and curl -6: sometimes only one path is broken.
3. TLS: a certificate error or a reset after Client hello
After Client hello the server should reply with Server hello and send its certificate. If certificate verification fails, curl reports SSL certificate problem. unable to get local issuer certificate and similar trust errors have a post of their own.
It's worse when the handshake just breaks off: Recv failure: Connection reset by peer right after Client hello, or silence until the timeout. openssl s_client -connect api.example.com:443 -servername api.example.com shows more. If the same command works from another network but not from yours, something along the way is interfering with connections based on the site name.
4. HTTP: what did the server say?
If TLS went through but no response comes, the server took the request and hung. curl ends it at --max-time with 0 bytes received. If a response does come, look at the code:
- 502 and 504: you reached the proxy, but the service behind it didn't answer it.
- 503: the service is overloaded or under maintenance. A
Retry-Afterheader sometimes says when to come back. - 429: you've hit a rate limit.
- 403 with no clear body: often bot protection or a country or IP filter, not your permissions.
For any of these curl exits with code 0: the HTTP exchange itself worked. To make a script notice, add --fail; the code becomes 22 and curl prints The requested URL returned error: 502.
Outage or block?#
A single error won't tell you which. To narrow it down, compare:
- The same request from another network. Mobile data, a server in another country, an online reachability check. If it works from there and not from you, the problem is on the path, not in the API.
- The service's status page. Big APIs have one; check it for an incident that matches what you see.
- Another client on the same machine. If the browser opens the URL and your script doesn't, look at the script's settings: proxy, certificates, DNS.
If the request fails from everywhere, the service is down. If it fails from one network only, and the steps above showed a reset or silence during TLS, it looks like interference on the path. Don't call it a block based on one reset: a server that's restarting looks exactly the same.
What you see in an API client#
Tetiva doesn't show per-phase timings (DNS, connect, TLS), only the total response time, so you find the layer with curl. Here's how those errors look in the client:
- Timeout. Tetiva waits up to 30 seconds for a response, then says
request timed out after 30s. While the request runs, a seconds counter ticks andCancelstops it. - DNS. The error reads
DNS resolution failed for "api.example.com". - Connecting. Connection errors other than DNS and timeouts show up as
connection refusedwith the server's address. For DNS, connection and timeout errors the client suggests what to check. - Resets and broken TLS. These come through as the raw error after
request failed:, for example…: read: connection reset by peer.
A failed attempt stays in History along with the error text. Filtering by the error status shows when the request stopped working. Cmd-click (Ctrl-click on Windows and Linux) the last good record and the first failed one, then press Compare to see what changed in the request.
What to send to the API's support#
When you contact support, include:
- the full
curl -voutput (swap theAuthorizationheader for a placeholder); - the time of the request, with time zone;
- your public IP and ISP;
- what
digsaid, and where the request works and where it doesn't.
If the request fails in a browser, attach a HAR file instead of curl output: how to record one and what to strip from it.
Cheat sheet#
- DNS:
dig +short host, compare resolvers, bypass withcurl --resolve. - TCP:
refusedmeans a closed port, a long timeout means packets don't arrive.nc -vz host 443. - TLS:
SSL certificate problemis the certificate, a break right after ClientHello is interference on the path.openssl s_client. - HTTP:
0 bytes receivedmeans the server hung, 502/504 means the service behind the proxy isn't answering, 429 is a rate limit. - Block or outage: the same request from another network.