返回指南
Troubleshooting·2026年7月17日·6 min read

Claude API 401 authentication_error / invalid x-api-key — every cause

A 401 from Claude is always one of five things: the wrong header, the wrong key type for the endpoint, a malformed env var, a revoked key, or the wrong base URL for that key. Run the diagnostic below and you'll find yours in under a minute.

A 401 from Claude is always one of five things: the wrong header, the wrong key type for the endpoint, a malformed env var, a revoked key, or the wrong base URL for that key. Run the diagnostic below and you'll find yours in under a minute.

The error

response (HTTP 401)
{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "invalid x-api-key"
  }
}

Causes and fixes at a glance

CauseFix
Wrong header for the endpointAnthropic's native API wants x-api-key + anthropic-version; OpenAI-compatible endpoints want Authorization: Bearer.
Key/endpoint mismatchsk-ant-… keys work only against api.anthropic.com; gateway keys (e.g. sk-kunavo-…) work only against their own gateway URL.
Whitespace or quotes smuggled into the env varRe-export without quotes/newlines; print len(key) to catch trailing \n from copy-paste.
Key revoked or workspace disabledMint a fresh key in the console and rotate it in your secret manager.

Reproduce with raw curl (removes your SDK from the equation)

If curl works but your app doesn't, the bug is in your env plumbing, not the key:

diagnose.sh
# Native Anthropic wire (works on api.anthropic.com and Kunavo /v1/messages)
curl -s https://api.kunavo.com/v1/messages \
  -H "x-api-key: $KUNAVO_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model":"claude-sonnet-4-6","max_tokens":16,"messages":[{"role":"user","content":"ping"}]}'

# OpenAI-compatible wire (Bearer header instead)
curl -s https://api.kunavo.com/v1/chat/completions \
  -H "Authorization: Bearer $KUNAVO_API_KEY" \
  -H "content-type: application/json" \
  -d '{"model":"claude-sonnet-4-6","max_tokens":16,"messages":[{"role":"user","content":"ping"}]}'

# Check the key isn't carrying whitespace
python3 -c "import os; k=os.environ['KUNAVO_API_KEY']; print(repr(k[:12]), len(k))"

Match the key prefix to the base URL

sk-ant-… → api.anthropic.com. sk-kunavo-… → api.kunavo.com/v1. Sending a gateway key to Anthropic (or vice versa) always 401s — the error message never says "wrong host," so this one hides in plain sight.

Rotate if the key ever touched a repo or log

If the key is correct and still rejected, assume revocation (automated scanners revoke leaked keys fast). Mint a new one and store it in a secret manager rather than .env files that get committed.

If you're calling through Kunavo

Kunavo keys (sk-kunavo-…) authenticate with either wire format — Authorization: Bearer on the OpenAI-compatible endpoints or x-api-key on the native Anthropic Messages endpoint — so whichever SDK you use, only the base URL changes. Keys are created and revoked instantly in the dashboard.

FAQ

Why does my key work in curl but not in my app?

Almost always env plumbing: a trailing newline from copy-paste, quotes included in the value, the variable not exported to the process, or a different env loaded in production. Print the repr and length of the key inside the failing process.

Can I use my Anthropic Console key on an OpenAI-compatible gateway?

No. Each service authenticates only its own keys: sk-ant keys belong to api.anthropic.com, gateway keys belong to the gateway. Get a key from whichever base URL you're calling.

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