OAuth error: timeout of 15000ms exceeded
A client-side stopwatch ran out. The CLI made an HTTP call as part of signing in, gave it 15 seconds, and abandoned it when no response had arrived. Nobody rejected your credential — you had not presented one yet — nothing was overloaded on your account, and no quota was involved. The request may well still have been in flight when the CLI stopped waiting.
That makes this the third distinct failure mode in the login flow, and the one most often mistaken for the other two. It is not “the server said no” and it is not “the network is down”.
Data as of 2026-09. Vendor limits and defaults change; check the official docs for current values before acting on any number below.
This is not the timeout you know how to change
The first instinct is to raise a timeout, and the first thing people reach for
is API_TIMEOUT_MS, which sets Claude Code’s per-request API timeout and
defaults to 600000 milliseconds. Changing it does nothing here. That variable
governs requests to the model API; this deadline belongs to the sign-in flow,
which is a different client doing a different job.
Nor is it CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS, which is a first-byte deadline
for streaming responses and is itself version-gated in the docs. Neither
variable is in the path that produced this message.
No configurable knob for the login deadline is documented in the official Claude Code docs, and the honest advice is to stop looking for one. If you find a value circulating on a forum, treat it as unverified. The productive direction is not to extend the deadline — it is to get the exchange under it.
Fifteen seconds measures latency, not reachability
This is the judgement that saves the most time. A deadline this short is crossed by paths that are working perfectly well and are merely slow. That is why the reader’s instinct — “my internet is fine, I’m browsing right now” — is simultaneously true and irrelevant.
Things that add whole seconds without breaking anything: a TLS-inspecting proxy that terminates and re-establishes the connection, a VPN that tunnels your egress through another continent, a DNS resolver that tries an unreachable IPv6 address before falling back, a corporate gateway that queues requests at peak hours, satellite or mobile links with high round-trip times.
None of those produce a failure you would notice anywhere else. Page loads absorb an extra second or two invisibly; a fixed 15-second budget does not.
The second thing this reframes: the deadline applies to the CLI’s own HTTP call, not to how long you spent clicking through the authorization page in the browser. People routinely assume they were too slow to approve the sign-in and start racing the clock on the next attempt. That is the wrong variable — going faster in the browser changes nothing, and believing otherwise turns a configuration problem into a personal one.
Telling the causes apart
It fails at almost exactly 15 seconds, every single time. A path that is consistently over the line. This is deterministic and will not resolve itself. Go to the network-path fixes below.
It fails sometimes and succeeds sometimes, with no pattern. A path sitting near the line. You can get logged in by persistence, but you have not fixed anything — the same path will fail again the next time a credential needs renewing, usually at the worst moment.
It fails instantly rather than after a wait. Then this is not your error.
An immediate failure with no elapsed time is a connection or certificate
problem, and it reports as OAuth error: fetch failed
instead. Check which message you actually have before acting on this page.
It only fails on the corporate network and works on a hotspot. Your egress path is the cost. This is the most common outcome of the hotspot test and it tells you exactly where to spend your effort.
It fails on every network, including a clean one, at a consistent interval. Look locally: a resolver misconfiguration, an IPv6 fallback delay, or a local security agent intercepting connections will follow you between networks.
It started when you connected to a VPN. Disconnect and retry the login once. A credential obtained off-VPN is usable on-VPN afterwards, because the long sign-in exchange only happens at login time.
Is retrying useful?
No — and the reason is worth understanding, because retrying sometimes appears to work.
Re-running /login re-runs the same race against the same fixed deadline over
the same path. If the path is consistently over the line, every attempt fails at
the same mark, and the only thing you accumulate is abandoned attempts. If the
path sits near the line, you may eventually get lucky — but a sign-in you can
only obtain by chance is not a working setup. It will fail again later, in a
context where you have less patience and no terminal.
There is no retry-after header on this failure and no documented base delay to
copy, so any wait you insert between attempts is a number you made up. Try once
more; if the second attempt also runs out the clock, treat the path as the
problem and work through the fixes below.
Fix by scenario
- Corporate proxy or TLS inspection — ask for the sign-in flow’s hosts to bypass inspection, or perform the login once from an unfiltered path. Note that the sign-in host is not the same name as the API host, so an allowlist that already permits normal Claude Code traffic may not cover it.
- VPN adding round-trip time — disconnect, log in, reconnect. The stored credential carries you afterwards.
- IPv6 fallback delay — this shows up as a suspiciously consistent multi- second penalty on every request. Fixing the resolver or the interface configuration removes it; it is not specific to Claude Code and your other tools are quietly paying it too.
- Mobile or satellite link — log in once from a low-latency connection. A high-round-trip path can be fine for ordinary use and still lose a 15-second race that includes several handshakes.
- You cannot change the network at all — do the sign-in on a machine that can, if your setup allows the credential to be provisioned there. Do not attempt to move a credential by pasting it into a chat, an email, a shared document, or a third-party site; anything that transits those should be considered burned.
How to confirm it’s fixed
Complete a sign-in on the network that was failing, then quit, relaunch, and send one real request. The relaunch matters: it proves the exchange produced a credential that was written and can be read back, which the login screen does not tell you.
Then do it a second time. A single success on a path that sits near the deadline is indistinguishable from luck, and this error’s defining property is that luck is available. Two clean runs in a row on the same path is the smallest evidence that actually means something — and if you needed three attempts to get one success, you have not fixed it, you have sampled it.
Related errors
Elsewhere in this cluster, the failures look similar and are not.
OAuth error: Request failed with status code 500
carries a status code, which proves the round trip completed — the opposite
situation from a deadline that expired with no answer. A
401 saying OAuth is not supported
means the sign-in worked and the endpoint simply refuses that credential type,
so no amount of network tuning applies. A bare
AxiosError: Request failed with status code 401
comes from the HTTP client with no vendor error body at all, which moves the
question to which client sent it. If you are unsure whether your login was
refused, unanswered, or too slow, the
AI coding error triage tool splits them on
exactly that question.