Skip to content

OAuth error: Request failed with status code 500

The most useful thing on this page is in the error string itself: there is a status code. A status code only exists if DNS resolved, TLS completed, any proxy in the path let the request through, a server received it, and a response came back. Everything in the “check your network, disable your VPN, flush your DNS” genre is aimed at failures that this message has already ruled out. This is also not a bad credential — you have not presented one yet — and not a quota or billing problem, which never surface during sign-in.

What failed is the exchange: the step where the CLI trades what the browser gave it for a usable credential. Something on the other end produced a server error while doing that.

What “the other end” actually is

Two different machines can produce this 500, and they need opposite responses.

The authorization server. A genuine fault at the vendor. You cannot fix it, and the correct behaviour is to wait rather than to churn through login attempts. The API error reference treats 500 with error.type: api_error as an internal error to retry with exponential backoff — that guidance is for the API layer, but the shape of the fault is the same: transient, server-side, not yours.

A middlebox forging one. A corporate egress proxy, a TLS-inspecting appliance, a captive portal, or a personal VPN’s HTTP filter can terminate the connection and return its own response. To the CLI that is indistinguishable from the real server misbehaving, because it is a well-formed HTTP response with a 5xx on it. This case is entirely yours to fix, and waiting for it to clear will take forever.

The test that separates them takes two minutes: run the same login from a network path with no proxy — a phone hotspot is the usual instrument. If the login completes there, nothing at the vendor was ever broken and you are looking at your own egress. If it fails identically on a clean path, the fault is upstream and there is nothing local to change.

That single test is worth more than any amount of reading response bodies, because a forged 500 and a real one look the same from inside the CLI.

The other cause: a code that cannot be exchanged twice

A browser-based sign-in ends by handing the CLI a short-lived authorization value that is redeemed exactly once. That has a consequence people run straight into: if you resubmit the same value — by re-pasting it, by pressing Enter on a stale prompt, by re-running a login that was interrupted rather than restarting it — the exchange is no longer valid, and the server has every right to fail it.

This is why so many reports of this error describe it as “it failed once and now it always fails”. The first failure may have been transient; every failure after it is the user faithfully re-feeding a value that has already been spent or has expired.

The observable: does the very first attempt in a completely fresh login flow fail, or only the attempts after the first? If a brand-new flow succeeds, the original 500 was noise and the persistence was self-inflicted.

Is retrying useful?

No — not the retry you are thinking of.

Pressing up-arrow and re-running the failed step resubmits an exchange whose inputs are already stale. That is the one action guaranteed not to work, and it is what most people do first. There is no retry-after here to honor and no documented base delay to copy, so inventing one would be guesswork.

What does work is starting the login over from the beginning — a new flow, a new browser round trip, new values. That is a different operation, not a retry, and it is the correct response to both a genuine transient vendor fault and a stale-code situation.

Bound it: start a fresh flow once. If a fresh flow fails the same way, stop restarting and run the clean-network test above, because you now have a deterministic failure and repetition is only costing you time.

Telling the causes apart

A fresh flow on a clean network path succeeds. Your normal network path is interfering. Look at the proxy, the inspection appliance, or the VPN — not at your account.

A fresh flow fails on every network path, and other people report the same thing at the same time. Vendor-side. Check the vendor’s status page and wait. Nothing in your configuration is implicated.

Only the repeat attempts fail; the first attempt of a fresh flow works. You were re-submitting a spent exchange. Nothing is broken.

The login succeeds but the credential is not there afterwards. Then the exchange was not the problem at all and you have a persistence problem instead; Invalid API key · Please run /login covers the case where a login reports success and the next request is still refused.

It only fails on one machine while an identical setup works elsewhere. Compare the two environments before blaming the vendor — a machine-specific proxy variable or a policy-managed setting is the usual difference.

Fix by scenario

  • Proxy or inspection appliance in the path — get the auth flow’s hosts allowed through, or run the login once from an unfiltered path and let the stored credential carry you afterwards. Note that the API host and the sign-in host are not the same name, so an allowlist that permits normal Claude Code traffic can still block the login.
  • Genuine vendor fault — wait, then start a fresh flow. Do not automate retries against a login endpoint.
  • Stale or re-used exchange — abandon the current attempt entirely and begin a new sign-in rather than reusing anything from the failed one.
  • Reporting it — capture what you can, but be careful what you attach. The docs are explicit that /heapdump’s .heapsnapshot file contains every string in the process, including the full conversation and credentials, and must not be posted publicly; only the accompanying -diagnostics.json is safe to share. The same logic applies to raw terminal captures during a login: screenshot the error line, not the whole scrollback.

Never paste a credential, an authorization value, or a callback URL into a chat, an issue tracker, or a third-party diagnostic site. A callback URL carries the exchange value in it, and it is as sensitive as a key while it lives.

How to confirm it’s fixed

A login that completes is necessary but not sufficient. Confirm in two steps: finish a fresh sign-in, then quit and relaunch, and send one real request. That proves the exchange produced a credential that was stored and can be read back — which is the outcome you actually wanted, and is not implied by the login screen saying it worked.

If you changed a proxy allowlist, repeat the whole flow on the corporate path rather than the hotspot you tested with. A fix validated only on the network that was never broken has validated nothing.

Same OAuth error: prefix, opposite meaning: OAuth error: fetch failed has no status code, which means no response ever arrived — read that page if your message lacks a number, because the entire diagnosis inverts. If the flow dies after a fixed interval instead, a login that times out at a fixed deadline is a latency problem rather than a server fault. And a 401 saying OAuth is not supported means the sign-in worked fine and the endpoint simply does not take that kind of credential. To decide which of these you are holding, the AI coding error triage tool sorts auth failures by whether the request was answered, unanswered, or refused.