AxiosError: Request failed with status code 401
A server was reached and it refused the credential it was given. The status code
alone rules out the whole “check your network” genre — DNS resolved, TLS
completed, a response came back — and it rules out quota, billing and capacity,
which arrive as 429, 402 and 529 with wording of their own. What it does not
tell you is whose credential was refused, or by whom. The most informative
thing in this message is the word AxiosError, because it identifies the code
that made the call, and that code is almost never the part of your setup you are
about to start debugging.
Data as of 2026-09. Vendor limits and defaults change; check the official docs for current values before acting on any number below.
What the missing half of the message is telling you
A 401 from the Claude API does not look like this. Per the API error reference, a
rejected credential comes back as 401 with an error object carrying
error.type: authentication_error and a message, and the response carries a
request_id (a request-id header, request_id in the body). Claude Code then
renders that condition in its own documented wording — the CLI has distinct
strings for a refused credential, for exhausted Console credits, and for a plan
limit, and none of them is a raw exception class with a number on the end.
So a bare AxiosError: Request failed with status code 401, with no type, no
message and no request id, is evidence about which layer threw it. Axios is a
general-purpose HTTP client. It shows up in the code around a model call —
installers and update checks, plugin and extension code, an MCP server talking to
its own vendor over HTTP, a wrapper script, a relay or gateway, a hook that calls
an internal service — and each of those carries its own credential to its own
host.
Treat the error as “some HTTP client in my toolchain was told no”, not as “my
Claude key is bad”. People lose an afternoon here: they rotate an Anthropic
key, re-run /login, regenerate it again, and the failing call never involved
that credential at all. The credential that failed and the credential you are
fixing are frequently two different secrets.
The first thing to capture: which host answered
You need three facts, none of which require the key itself.
- The request URL. An axios error carries the request configuration it failed on, including the URL and headers it sent. Print the host. If it is a package registry, an internal service, a proxy, or a gateway host you set yourself, you are done diagnosing and the rest of this page is about your environment rather than Anthropic.
- Whether a
request-idcame back. Anthropic responses carry one. A 401 with no request id is unlikely to have come from the API at all; a 401 with one did, and then the question becomes which credential your process sent. - Whether the response carries
WWW-Authenticate. An intermediary that wants its own credentials — a corporate proxy, a registry, a reverse proxy in front of an OpenAI-compatible or Anthropic-compatible endpoint — will normally challenge you that way. The API has no reason to.
If you cannot get at the error object because the failure happens inside a tool
rather than inside your own code, run the failing operation with the tool’s debug
output enabled. Claude Code writes a per-session debug log under
~/.claude/debug/; on Windows ~ means %USERPROFILE%. One line naming the host
replaces an hour of guessing.
Is retrying useful?
No. A 401 is a verdict computed from credentials that did not change between attempts.
There is no retry-after to honor, no documented base delay to copy, and no
server asking you to wait. The official Anthropic SDKs retry connection errors,
rate limits and 5xx responses with exponential backoff — twice by default — and
401 is deliberately not in that set. Claude Code’s own retry machinery has
already run by the time you see most of its errors, with a default of ten
attempts, and it does not turn a refusal into an acceptance either.
Axios itself adds no retry behaviour of its own, so unless something in your code wrapped the call in a loop, the exception in your hands is the first and only attempt. If something is looping — a job runner, an agent re-invoking a failed tool, a retry decorator — turn it off for this class before you debug anything else. Repeated identical failures cost you time and make the logs harder to read.
Press Enter again once if you like; when the second attempt dies the same way, you have confirmed a deterministic failure and the rest of this page applies.
Telling the causes apart
The URL is not an Anthropic host. Something else refused you: a private npm registry, an internal API, a proxy, or a self-hosted gateway. Fix the credential that host expects. Nothing about your Claude sign-in is implicated, and changing it is wasted work.
The URL is a gateway host you configured. A base URL override points your traffic at a relay with its own credential expectations. A relay that wants an API key will not accept a subscription sign-in, no matter how cleanly the sign-in completed — a 401 that says OAuth is not supported is the explicit version of the same mismatch.
The URL is the API and a request id came back. Then a real Anthropic credential was sent and rejected: malformed, revoked, expired, or belonging to a different organization. Those are four different repairs and only the first is free.
It fails in one tool and not in another on the same machine. Different processes, different environments. A shell you edited an hour ago and a long-running editor process started yesterday do not hold the same variables.
It started after an install, an update, or a plugin change. Suspect the change. An installer or update check that authenticates to a registry produces this exact string while every model request keeps working — which is why the tool appears half-broken rather than logged out.
Fix by scenario
- A non-Anthropic host refused you — repair that host’s credential where it lives (registry config, proxy credentials, service token). Rotating an API key changes nothing here.
- A gateway is in the path — confirm what your base URL is set to and what that endpoint accepts. Match the credential type to the endpoint rather than repeating the login.
- A genuine Anthropic 401 — replace the key rather than repairing it: a
malformed, revoked or expired credential cannot be fixed in place. Set it in
exactly one place, then verify which credential is active — Claude Code’s
/statusreports the active credential source, and that is the only step here that reports state instead of guessing. - Two credentials in play — remove the loser rather than adding overrides. A stray environment key outranking a subscription is a whole failure mode of its own, covered in Invalid API key · Please run /login.
- Nothing matches — run
claude doctorfrom the shell for a read-only installation and settings check, which works even when a session will not start.
Never paste an API key, a token, or a callback URL into a chat window, an issue tracker, a web form, or a third-party “key checker”. Check properties, not contents: whether the variable is set, its length, and whether it has trailing whitespace. Mask anything you must quote — the last few characters are enough to tell two keys apart and useless to anyone else. A key that has been pasted somewhere it should not be is a key to rotate in the vendor console.
How to confirm it’s fixed
A single success is enough, because nothing about a 401 is intermittent — but it
has to be the right success. Re-run the operation that failed, from a freshly
started process, on the machine that was failing, and confirm the call that was
throwing now reaches its own host. If your fix was to the environment, open a
terminal you have not used since the edit; a fix that only works in the window
where you typed unset is not a fix.
If the call was an Anthropic one, confirm a response carries a request-id. That
proves you reached the API rather than getting an agreeable answer from a cache,
a mock, or a proxy.
Related errors
- Invalid API key · Please run /login
is what a refused Claude credential looks like when the CLI’s own error path
produced it — read it if your message names
/loginrather than axios. - OAuth error: Request failed with status code 500 is the same “a status code came back” reasoning applied to sign-in rather than to an API call, where the fix is to restart the flow rather than to retry it.
- OAuth error: fetch failed is the inverse case: no status code at all, so nothing answered and no credential was ever judged.
- The AI coding error triage tool sorts these by the signals used above — whether a status code exists, whether a request id exists, and whether the body came from the vendor.