invalid_api_key (401): Incorrect API key provided, fixed

The short version
invalid_api_keyis OpenAI's 401 for a key it cannot authenticate. The message starts withIncorrect API key provided.- Anthropic's version is a 401
authentication_errorwith the messageinvalid x-api-key. - The usual culprits are stray whitespace, an unloaded environment variable, or a key from a different service.
- One
curlcall tells you whether the key or your code is at fault.
If nothing changed in your code, consider that the key may have been revoked.
What the error looks like
Calling OpenAI with an invalid key returned this 401 on November 10, 2026. The key is partly masked in the response:
{
"error": {
"message": "Incorrect API key provided: sk-doc-c****************-000. You can find your API key at https://platform.openai.com/account/api-keys.",
"type": "invalid_request_error",
"param": null,
"code": "invalid_api_key"
}
}
With no auth header at all, you get a 401 whose message starts with You didn't provide an API key. and whose code is null.
Anthropic's authentication_error
The Anthropic API returned this 401 for an invalid key on the same day (the ID is illustrative):
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "invalid x-api-key"
},
"request_id": "req_011CgvQYVzMW2xSesgpXWSRA"
}
Anthropic's docs name malformed, revoked and expired keys as causes.
Common causes
| Cause | How to check |
|---|---|
| Whitespace or a newline around the key | Print its length, or strip() it in code |
| Environment variable not loaded | Print the length from the same shell |
| A deleted or deactivated key | Create a new key and swap it in |
| A key from another organization or project | Check where it was issued |
| An OpenAI key sent to a different service | Check that base_url and key match |
| Wrong header type | Check Authorization versus x-api-key |
OpenAI's error code guide covers the first few.
Isolate it with curl
Check the length and the final byte without printing the key:
echo "${#FASTMETAL_API_KEY}"
printf '%s' "$FASTMETAL_API_KEY" | tail -c 1 | od -c
Then list the models. A 200 means the key is fine and the problem is in your code:
curl -s -o /dev/null -w "%{http_code}\n" \
https://api.fastmetal.ai/v1/models \
-H "Authorization: Bearer $FASTMETAL_API_KEY"
In Python, strip the value when you load it:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["FASTMETAL_API_KEY"].strip(),
base_url="https://api.fastmetal.ai/v1",
)
print(len(client.models.list().data))
FastMetal keys
FastMetal keys start with sk- (USD keys with sk-usd-) and are shown once, at creation. Send them as Authorization: Bearer. If you lose one, create a new one.
Claude Code needs one specific variable. ANTHROPIC_API_KEY goes out as an x-api-key header, which FastMetal rejects, so use ANTHROPIC_AUTH_TOKEN:
export ANTHROPIC_AUTH_TOKEN="$FASTMETAL_API_KEY"
export ANTHROPIC_BASE_URL="https://api.fastmetal.ai"
Leave /v1 off the base URL. With it, Claude Code requests /v1/v1/messages and gets a 404. The full setup is in the Claude Code guide. Rates are on the pricing page.
FAQ
Why does a brand-new key return 401?
Check for a clipped end or surrounding whitespace from copying. After changing an environment variable, restart the shell or server.
Why is the type invalid_request_error on a 401?
That is how OpenAI's body is built: type is invalid_request_error and code is invalid_api_key. Branch on the code or the HTTP status.
Can I hardcode the key?
Do not. Load it from the environment or a secret manager and keep it out of the repository. Revoke and replace any key that may have leaked.
Can I use an OpenAI key with FastMetal?
No. Use a key issued by FastMetal and set base_url to https://api.fastmetal.ai/v1.
Wrapping up
For a 401, check whitespace, then the environment variable, then the pairing of key and endpoint. A curl call to the model list settles whether the key works.
To get a FastMetal key, create a free account.