Claude API Key Not Working? Troubleshooting Guide
If your Claude API key stopped working, the cause is almost always one of five things: the key is malformed or copied incorrectly, it was revoked or rotated, your account has a billing or quota problem, you're hitting a rate limit that looks like an auth error, or you're sending the request with the wrong headers or endpoint. This guide walks through each case with concrete checks you can run in under five minutes.
Before anything else, isolate the problem. Run the simplest possible request against the API with your key and nothing else — no SDK, no retry logic, no middleware. If the bare request fails, the problem is the key or your account, not your code.
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 16,
"messages": [{"role": "user", "content": "hi"}]
}'
Whatever error comes back here is the real error. Everything below maps common responses to fixes.
"Invalid API key" / 401 Unauthorized
This is the most common message and the least specific. Check these in order:
- Whitespace or truncation. Keys copied from a terminal or
.envfile often pick up a trailing newline or lose the last character if the terminal wrapped the line. Print the key's length and first/last few characters to sanity-check it:echo -n "$ANTHROPIC_API_KEY" | wc -c. - Wrong environment variable. If you have multiple projects or shells open, you may be exporting an old key in one terminal session and a new one in another. Restart your shell or explicitly
unsetand re-export. - Key revoked or rotated. If someone on your team regenerated the key in the console, the old one stops working immediately with no grace period. Check the console for the key's creation date and status.
- Using the wrong header. Anthropic's native API expects
x-api-key, notAuthorization: Bearer. Mixing this up — common when copy-pasting code written for OpenAI or another provider — produces an auth failure that looks identical to a bad key.
403 Forbidden
A 403 usually means the key is valid but doesn't have permission for what you're asking:
- The key belongs to an organization or workspace that doesn't have access to the model you requested (for example, a newer model not yet enabled on your plan).
- The key was created with restricted scopes and doesn't have permission for the endpoint you're calling.
- Your account's billing details are missing or a payment failed, which some providers treat as a soft lockout rather than a clean "no credit" error.
Check your provider's billing and usage dashboard directly — don't assume the error message tells you the real cause.
429 Rate Limited (looks like an auth error in some setups)
If you're calling the API through a proxy, gateway, or custom wrapper, a 429 from the upstream provider sometimes gets rewritten into a generic 401/403 by middleware that doesn't forward status codes correctly. If your bare curl test above succeeds but your app fails, the problem is in your application layer, not the key. Add logging at the point where you build the request headers and confirm the exact key value being sent at runtime — not the one in your .env file, the one actually in the process's environment.
Key works in one place but not another
This is almost always an environment variable scoping issue:
- Local vs. deployed. Your
.envfile works locally, but the deployment platform (Vercel, Render, Railway, etc.) has its own environment variable settings that weren't updated when you rotated the key. - Multiple
.envfiles. Frameworks like Next.js load.env.local,.env.development, and.env.productiondifferently. A key set in the wrong file silently gets ignored. - Docker builds caching an old key. If the key is baked into a build arg rather than passed at runtime, rebuilding without
--no-cachecan leave a stale value.
A quick way to confirm what's actually being sent: temporarily log process.env.ANTHROPIC_API_KEY.slice(-4) (last four characters only) right before the request fires, and compare that against the key shown in your provider dashboard.
When the root cause is deeper than one key
If you're managing Claude access for a team — multiple developers, multiple apps, shared billing — raw provider API keys get painful to troubleshoot at scale. There's no built-in way to see who used which key, no per-app key rotation without breaking other services, and one person regenerating a key in the console can silently take down everyone else's integration.
This is the problem SubToAPI solves: it sits on top of your Claude access and issues separate, independent sub_live_... API keys per application or environment, each with its own usage metadata, so a key you need to rotate in one place doesn't cascade into outages elsewhere. You get streaming, tool use, and team seats, with a dashboard that shows exactly which key did what. If you're debugging "which key is this and who owns it" as often as you're debugging actual code, that's worth fixing at the infrastructure level rather than per-incident. Check the quickstart to see how key issuance and request logging work, or compare plans if you're managing more than one integration.
A fast troubleshooting checklist
- Run the bare curl request above — isolate app code from the key itself.
- Check for whitespace, truncation, or stale shell exports in the key value.
- Confirm the key hasn't been revoked or rotated in the provider console.
- Verify billing status and model access permissions, not just the error text.
- Check that the deployment environment has the current key, not just local
.env. - If using a gateway or proxy, confirm it forwards the real status code instead of masking rate limits as auth errors.
Why does my Claude API key work in curl but not in my app?
This almost always means your application is reading a different value than you think — a stale environment variable, a .env file that isn't loaded in that environment, or a build that cached an old key. Log the actual key value (or its last few characters) at request time to confirm.
Why did my Claude API key suddenly stop working with no code changes?
The most common causes are key rotation or revocation by a teammate, a billing issue flagged on the account, or a rate limit being hit after increased traffic. Check the provider's console for key status and billing before assuming a bug in your code.
Is "invalid API key" the same error for expired, revoked, and malformed keys?
Often yes — many providers return a generic 401 message regardless of the specific cause, which is why isolating the problem with a minimal curl request matters more than reading the error text closely.