Skip to content

API Error (Connection error.) · Retrying in 1 seconds… (attempt 1/10)

The label in parentheses is the whole diagnosis: the request produced no HTTP response at all. There is no status code, no error.type, and no request_id, which rules out the four things people reach for first — a 429 rate limit, a 529 overload, an authentication rejection and a billing block. Every one of those arrives as a response and gets labelled with its status in this same banner. A retry counter is also not evidence that you are being throttled, which is the most common misreading of the line.

Data as of 2026-09. Vendor limits and defaults change; check the official docs for current values before acting on any number below.

The banner is a classification verdict, and it has already ruled things out

Claude Code retries transient failures up to ten times with exponential backoff before showing you a terminal error. The important part is not the ten — it is that the retry list is selective, and the documented exclusions are specific.

TLS certificate validation failures are reported on the first attempt, with no retries. So are failures arriving after Claude has already completed a block of text or a tool call, because re-running those could execute the same tool calls twice. Neither category ever produces an attempt counter.

Follow that through and the banner is doing free work for you. Seeing attempt 1/10 at all has already eliminated a certificate problem, and told you the failure landed before Claude committed to any output. Two of the most expensive branches in a normal connection-error investigation — corporate TLS inspection, and a half-finished turn you must not replay — are closed before you change a single setting. The same string without a counter, failing instantly, means the opposite and belongs to TypeError (fetch failed).

It also tells you something about time. Exponential backoff means the intervals grow, so ten attempts do not span ten seconds; they span a window that widens with each retry. Reaching attempt 10 is not ten pieces of bad luck — it is one condition that outlived the entire backoff window. That is a much stronger signal than the banner’s cheerful tone suggests, and it is the moment to stop waiting and start diagnosing.

Whose counter is it

The ten comes from CLAUDE_CODE_MAX_RETRIES, a setting belonging to the CLI. It is not your SDK’s retry count: the official Anthropic SDKs retry transient failures twice by default. If you have set max_retries in code somewhere, this banner is not it and changing that value will not move the numbers you are watching. The same counter appears on unrelated failures for the same reason — a 503 with no healthy upstream walks through what the loop does and does not accomplish.

Two banners that look the same and are not

Confusing these costs people a working session, because the response is opposite in each case.

Retrying in Ns · attempt x/y means a request failed and this is attempt number x. Waiting for API response · will retry in … · check your network means no data has arrived for about twenty seconds and the request has not failed yet — it is still open, and the work may still land. Killing the second one because it looks like the first throws away a turn that was in progress. If waiting rather than failing is what you are watching, read No response from API, retrying in 2m 25s instead of this page.

Is retrying useful?

Yes — and it is already happening. Your job is to read the sequence, not to start it.

Connection failures of this shape are usually transient, and the built-in loop resolves most of them without you doing anything. Let it run once. What you are watching for is the shape of the sequence, because it is the diagnosis:

  • One or two attempts, then the turn completes. Transient. Nothing to fix unless it becomes frequent.
  • The counter climbs steadily to the cap on most requests. A stable condition on your path. More attempts will not find a different answer.
  • It fires on some requests and not others in the same session. Something is load- or size-dependent rather than broken outright.

The cheap wrong fix is raising the retry count — whether by setting CLAUDE_CODE_MAX_RETRIES higher or by reaching for the retry watchdog variable that extends retrying further. If attempts 1 through 10 all failed identically, attempts 11 through 30 are the same request, over the same path, to the same resolver. You are buying a longer hang, not a different outcome. The watchdog exists for capacity errors, where waiting genuinely is the strategy; a connection error that produced no response is not that.

Telling the causes apart

Does a trivially small request fail the same way? Send the shortest possible prompt. If it fails identically, the failure is independent of your payload and you can stop looking at context size, model choice and attachments entirely.

Does it reproduce on a different network? Phone hotspot, a different machine, a cloud shell. Corporate egress proxies, VPN split tunnels and inspecting middleboxes sit in exactly the position that produces a response-less failure. If the other network is clean, the fault is local to yours.

Did it start after an infrastructure change? A new VPN client, a container base image bump, a DNS resolver change, new egress rules. Suspect the change before you suspect the vendor, and roll it back far enough to prove which side owns the problem.

Are you pointed at a custom base URL or a gateway? Then the connection that failed was to them, not to Anthropic, and no amount of work on your account will help. Send the same request straight at the official endpoint to confirm.

Does /status show the credential you expect? Not because a credential causes a connection error — it cannot — but because a stray environment variable routing you through a different base URL or a different provider changes the host you are failing to reach. This is a five-second check that occasionally ends the investigation.

Is anyone else seeing it right now? If the failure is general and brief, it is upstream and the answer is to wait. Check the vendor status page before spending an afternoon on your own configuration.

Fix by scenario

  • Small requests fail too, on one network only — fix the path: exempt the API host from the inspecting proxy, or route around the VPN. Re-test from the failing network, not the clean one.
  • Started after a change — revert the change first and confirm the banner stops. Diagnosing forward from a broken state is slower than proving which edit did it.
  • Custom gateway in the path — switch to the direct endpoint to isolate, then take it up with whoever runs the gateway. Keep a one-command way to flip between routes; it turns a two-hour investigation into a two-minute one.
  • Intermittent, unrelated to size or network — let the loop absorb it. This is what it is for, and it is already doing it.
  • Reporting it — there is no request_id for a failure that produced no response, and there never will be. Capture what does exist instead: the exact timestamp with timezone, the base URL actually in effect, whether small requests also fail, and whether a plain request from the same machine reproduces it.

How to confirm it’s fixed

A single successful request proves nothing here, because the loop was already producing successful requests most of the time. Confirm against a full session of ordinary work with no banner at all, then repeat it once. The failure is intermittent by nature, so the absence of one occurrence is not evidence; the absence across a workload that used to produce several is.

If your fix was a route or proxy change, verify it is in effect at runtime rather than in the file you edited — print the base URL and proxy the process is actually using, from a freshly launched session.

The neighbours in this cluster are told apart by what survived the failure. If your code caught a typed exception rather than watching a banner, you have anthropic.APIConnectionError: Connection error, and the useful content is the exception’s underlying cause. If the stream was cut after partial output had already arrived, see connection closed mid-response, where the ordering of the 200 explains why no automatic retry applies at all. If the cut came after a measurable quiet interval you can move by editing a number, it is a stream idle timeout. When you are not sure which of them you are holding, the AI coding error triage tool sorts them by the signals used above: whether a response arrived, whether output arrived, and whether a retry counter appeared at all.