AuthenticationError 401: Incorrect API key provided (OpenAI / Anthropic)
The API received a key it does not recognise — wrong variable, stray quotes or whitespace, or a revoked key. Check what the client actually loaded, not what you think you set.
Updated
The error
openai.AuthenticationError: Error code: 401 - {'error': {'message': 'Incorrect API key provided: sk-proj-********. You can find your API key at https://platform.openai.com/account/api-keys.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_api_key'}}Anthropic's version:
anthropic.AuthenticationError: Error code: 401 - {'type': 'error', 'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}}What it means
The request reached the provider, and the key attached to it is not valid for any account. This is different from a rate limit or a billing block: the server does not know who you are at all. In almost every case the code sent something other than the key you believe it sent.
Why it happens
The gap between "I set the key" and "the client received the key" has many small cracks:
- The environment variable is set in one shell, and the script runs from another (or from an IDE that inherits neither).
.envfile exists, butload_dotenv()is missing or runs after the client is created.- The value carries invisible baggage: surrounding quotes copied into the
.env, a trailing newline or space, or a truncated paste. - The variable name is close but wrong:
OPEN_AI_API_KEY,ANTHROPIC_KEY. - The key was rotated or revoked — for example, automatically, after being committed to a public repository.
How to fix it
1. Print what the process actually has — length and edges, never the whole key.
import os
key = os.environ.get("OPENAI_API_KEY")
print(repr(key[:7]), len(key) if key else None)'sk-proj' 164
None means the variable never reached the process. A repr showing '"sk-pro' or a length off by one exposes quote and whitespace stowaways.
2. Load .env before creating the client, and store the value bare.
from dotenv import load_dotenv
load_dotenv() # first
from openai import OpenAI
client = OpenAI() # then# .env — no quotes, no spaces around =
OPENAI_API_KEY=sk-proj-xxxxxxxxxxxx
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxx3. Restart what needs restarting. New environment variables reach only new processes. Reopen the terminal; on Windows, setx affects future terminals only. IDEs and Jupyter servers need their own restart.
4. If the machine's value is right and 401 persists, the key itself is dead. Generate a fresh key in the provider console, update the .env, and check you are in the intended organisation/workspace — keys are scoped to one.
5. If the key ever touched a public repo, rotate it now. Providers scan public code and revoke exposed keys; the 401 was the mercy. Add .env to .gitignore before the next commit.
How to prevent it
One pattern everywhere: keys live in .env (gitignored) or a real secrets manager, loaded at startup, accessed by exactly one canonical variable name. A startup assertion — key present, expected prefix — turns silent misconfiguration into an immediate, clear failure.
Related errors
- RateLimitError 429 — the key works, the quota does not
- Model not found (404)
- Your credit balance is too low (Anthropic)
- APIConnectionError