Anthropic Error: authentication_error — Invalid API Key
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY from env
try:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=64,
messages=[{"role": "user", "content": "ping"}],
)
except anthropic.AuthenticationError as e:
# e.status_code == 401
# e.body['error']['type'] == 'authentication_error'
# e.body['error']['message'] == 'invalid x-api-key'
...
authentication_error is Anthropic’s auth-layer rejection: HTTP 401 with structured error type authentication_error and a message like invalid x-api-key. The auth check happens before any model invocation, so the error is always about credentials — never about the prompt, the model, or rate limits. If you see it, the bytes you’re sending in the x-api-key header don’t match an active key in Anthropic’s registry.
The fix is almost always boring: an env var that didn’t load, a key that was rolled, a Workspace mismatch, or whitespace creeping in from a copy-paste. Add a startup assertion that prints the key prefix and length, fail fast if anything’s off, and you’ll catch 90%+ of these errors before they reach a customer. The remaining 10% are key rotations and Workspace scope changes, both of which the Anthropic Console reveals in seconds.
Why this happens
- Environment variable is undefined or empty. If `ANTHROPIC_API_KEY` is missing, the SDK sends an empty `x-api-key` header (or fails fast in some versions). Common in Vercel/Netlify when an env was added but the deployment wasn't rebuilt; in Docker without `--env-file`; in Lambda missing the env config.
- Key was rolled or deleted in the Console. If a teammate rolled the key after a leak, every old copy stops working immediately. Anthropic also auto-revokes keys exposed publicly (GitHub scanning). console.anthropic.com → Settings → API Keys shows last-used timestamp and revocation history.
- Workspace-scoped key used outside its workspace. Anthropic supports Workspaces (similar to OpenAI projects). A Workspace API key only authenticates calls scoped to that workspace. Using it against the org-level endpoints, or across workspaces, fails `authentication_error`.
- Bedrock or Vertex credentials sent to direct Anthropic API. AWS Bedrock and GCP Vertex use IAM/AWS-Sig-V4 and OAuth-style auth respectively, not `x-api-key`. Code paths sometimes get crossed — a Bedrock-only credential set is presented to the direct Anthropic SDK and fails 401. Each provider needs its own SDK and credential type.
- Whitespace, smart quotes, or wrong header in copy-paste. Copy-pasting a key from chat or a doc can introduce trailing whitespace, smart quotes, or invisible Unicode. The key prefix is right but the bytes don't match. Some SDKs send the literal string `Bearer sk-ant-...` if you paste a Bearer-style header into a key field; Anthropic expects raw key in `x-api-key`.
How to fix it
Fixes are ordered by likelihood. Start with the first one that matches your context.
1. Print the key prefix and length at startup
Never log the full key. Log the prefix (first 12 chars) and length so you can spot truncation, wrong format, or env-var miss without exposing the secret. Add a startup assertion that fails fast on misconfiguration.
import os, sys
key = (os.environ.get("ANTHROPIC_API_KEY") or "").strip()
if not key:
sys.exit("ANTHROPIC_API_KEY is missing")
if not key.startswith("sk-ant-"):
sys.exit(f"Wrong key prefix: {key[:12]}… (expected sk-ant-)")
if len(key) < 90:
sys.exit(f"Key looks truncated: length {len(key)}")
print(f"Anthropic key OK: prefix={key[:12]}… length={len(key)}")
2. Strip whitespace and quotes before passing to the SDK
Bash and `.env` files sometimes pass through quotes or trailing newlines, especially on Windows. Trim aggressively before initialising the client.
import Anthropic from '@anthropic-ai/sdk';
const raw = process.env.ANTHROPIC_API_KEY ?? '';
const apiKey = raw.trim().replace(/^['"]|['"]$/g, '');
if (!apiKey.startsWith('sk-ant-')) {
throw new Error(`Bad ANTHROPIC_API_KEY prefix: ${apiKey.slice(0, 12)}`);
}
const client = new Anthropic({ apiKey });
3. Verify in the Console that the key is active
console.anthropic.com → Settings → API Keys lists every key with creation date, last-used timestamp, and revocation status. Locate yours by the last 4 characters and confirm it's not "Revoked." If "Last used: Never" but you're sending it, you have a transit problem (header missing, env not loaded). If revoked, generate a new one and rotate it through your deploys.
4. Check workspace scope and switch if needed
In multi-workspace orgs, each workspace has its own keys. Confirm the workspace that owns the key matches the workspace your code is calling against. Workspace-scoped errors usually report `authentication_error` rather than a more specific scope error — Console → Workspaces shows which keys belong where."
5. Use the right SDK for the right provider
Direct Anthropic API → `anthropic.Anthropic()` (Python) / `Anthropic` (TypeScript), env `ANTHROPIC_API_KEY`. AWS Bedrock → `boto3` or `@aws-sdk/client-bedrock-runtime`, AWS credentials. GCP Vertex → `google-cloud-aiplatform`, GCP service account. They are not interchangeable. If your codebase supports both, isolate the credential plumbing per provider."
Detection and monitoring in production
Alert on any `AuthenticationError` immediately — they should be near-zero in steady state. A burst usually means a deploy shipped with a wrong env, someone rolled the key, or Anthropic's exposed-key scanner revoked it. Tag the alert with the key prefix's last 4 chars (never the full key) so you can correlate to a specific rotation event.
Related errors
- anthropicrate_limit_errorYou exceeded one of Anthropic's per-minute caps for the model and tier — RPM (requests/min), ITPM (input tokens/min), or OTPM (output tokens/min). Anthropic enforces all three independently and you can hit any one without breaching the others.
- anthropicoverloaded_errorAnthropic's infrastructure is at capacity for the model you requested. This is server-side, not a problem with your code or your account — Claude is experiencing a traffic spike or capacity event and rejecting requests until load eases.
- stripeapi_key_invalidThe API key you sent in the `Authorization: Bearer ...` header doesn't match any active Stripe key — usually because of a test/live mode mismatch, a deleted or rolled key, copy-paste corruption, or a missing environment variable falling through to `undefined`.
- openairate_limit_exceededYour account has exceeded its per-minute request (RPM) or per-minute token (TPM) limit for the model you're calling. Limits are tier-based and per-model.
- openaiinsufficient_quotaYour OpenAI organisation has run out of paid credit, hit its monthly hard limit, or hasn't added a payment method yet. Despite the 429 status, this is a billing problem — not a rate-limit problem — and retrying won't help.
Frequently asked questions
What's the format of an Anthropic API key? +
Why is the auth header `x-api-key` and not `Authorization: Bearer`? +
How do I rotate an Anthropic key without downtime? +
Are Anthropic API keys scoped by Workspace? +
Will Anthropic auto-revoke keys exposed in public GitHub repos? +
Why does the Bedrock SDK never throw `authentication_error`? +
Can a single API key serve multiple environments (dev/staging/prod)? +
Does the SDK validate the key format before sending the request? +
When to escalate to Anthropic support
Open a support ticket only if (a) the Console shows the key as active and last-used recently but every request returns 401, suggesting an account or routing issue on Anthropic's side, (b) Anthropic's auto-revoke flagged a key that wasn't actually exposed, or (c) Workspace permissions are inconsistent with what's configured. For wrong-env, rolled-key, or copy-paste issues, the fix is in your code or hosting environment.