Back to guides
Troubleshooting·August 28, 2026·6 min read

Claude Code “API Error: 401 authentication_error” with a custom base URL — every cause

A 401 here is about your credential or your base URL, never your model — a model problem returns 404 with a message naming the model. That single distinction resolves most of these in one curl.

Last reviewed on .

A 401 here is about your credential or your base URL, never your model — a model problem returns 404 with a message naming the model. That single distinction resolves most of these in one curl.

The error

terminal
API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"Missing or invalid API key"}}

Causes and fixes at a glance

CauseFix
ANTHROPIC_API_KEY set where ANTHROPIC_AUTH_TOKEN was meantUse AUTH_TOKEN for a third-party base URL; API_KEY takes a one-time approval prompt.
Base URL carrying a /v1 pathSet the origin only — Claude Code appends /v1/messages itself.
Key revoked, or the account suspendedBoth answer 401, never 403. Mint a fresh key and check the account.
A model the Messages endpoint does not serveThat returns 404 naming the model, not 401 — so it is a different fix.

Print the three variables and check the base URL has no path

The most common cause is visible here. The base URL must be an origin — no /v1, no trailing path — because the client appends the endpoint itself. A base URL ending in /v1 produces a request to /v1/v1/messages.

check-env.sh
env | grep -E '^ANTHROPIC_(BASE_URL|AUTH_TOKEN|API_KEY|MODEL)='

# Right: https://api.kunavo.com
# Wrong: https://api.kunavo.com/v1

Call the endpoint directly, both ways

Kunavo's /v1/messages accepts the credential as either x-api-key or Authorization: Bearer, which is why Claude Code needs no plugin or proxy in front of it. If curl succeeds and the CLI does not, the problem is in your shell environment rather than on the server.

probe.sh
curl -s https://api.kunavo.com/v1/messages   -H "x-api-key: $ANTHROPIC_AUTH_TOKEN"   -H "anthropic-version: 2023-06-01"   -H "content-type: application/json"   -d '{"model":"claude-sonnet-5","max_tokens":8,
       "messages":[{"role":"user","content":"hi"}]}'

# Same call, other header style — both are accepted:
#   -H "Authorization: Bearer $ANTHROPIC_AUTH_TOKEN"

Unset the variable you are not using

If both ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN are set, the wrong one can win. Unset ANTHROPIC_API_KEY, start a new shell, and try again — a stale export in a shell profile outlives every other fix you try.

If the status is 404, stop debugging the key

A 404 whose message names the model means the credential was accepted and the model string was not. Fix ANTHROPIC_MODEL instead; nothing about the key is wrong.

If you’re calling through Kunavo

A 401 from Kunavo narrows to exactly three causes: the key does not carry the sk-kn- prefix, the key has been revoked, or the account is suspended. None of them answers 403, so the status code alone tells you which family you are in — and a valid key aimed at a model the Messages endpoint does not serve returns 404 with the model named in the message, not 401. That is the whole diagnostic tree.

FAQ

Why does my key work in curl but not in Claude Code?

Almost always a second variable set in a shell profile, or a base URL with a path on it. The endpoint accepts both header styles, so the difference is not the header.

ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY?

AUTH_TOKEN for a third-party base URL — it is used immediately. API_KEY triggers a one-time approval prompt first, which is often mistaken for a failure.

Does a Claude subscription cover a custom base URL?

No. A subscription authenticates to the vendor's own endpoint; pointing the CLI elsewhere means that endpoint's credential, billed by that endpoint.

Related guides

More error semantics live in the error reference; getting a key takes a minute via sign up and the authentication docs.