OpenAI AuthenticationError: invalid API key — 6 causes in diagnostic order
If the OpenAI API just returned HTTP 401 with AuthenticationError: Incorrect API key provided, you're not hitting a rate limit and you're not being blocked — the server simply doesn't recognize your key. This page walks through the six most common causes in the order you should check them, plus a one-liner to verify the key is valid before touching any code.
The 30-second answer
- What it looks like: HTTP 401,
AuthenticationError, message "Incorrect API key provided: sk-..." - Verify first: run
curl https://api.openai.com/v1/models -H "Authorization: Bearer $OPENAI_API_KEY"— if that 401s, the key itself is the problem. - Most common cause: the key was copied with a trailing space or newline, or it was deleted from the dashboard.
- Project key gotcha:
sk-proj-keys are scoped to a project — using them on org-level endpoints causes 401.
What the error looks like
The raw HTTP response is always:
HTTP/1.1 401 Unauthorized
{
"error": {
"message": "Incorrect API key provided: sk-proj-...Abcd. You can find your API key at https://platform.openai.com/account/api-keys.",
"type": "invalid_request_error",
"param": null,
"code": "invalid_api_key"
}
}
In the Python SDK this surfaces as an openai.AuthenticationError exception. In the Node.js SDK it's an AuthenticationError from openai/error. The code field is always invalid_api_key — distinct from account_deactivated and other auth-adjacent codes.
Cause 1: Wrong key was copied
OpenAI's dashboard shows the full key exactly once, at creation time. After that it's masked. If you didn't save the key immediately, you cannot retrieve it — you need to create a new one. Check platform.openai.com/api-keys and look at the key prefixes listed there. If the prefix on the error message doesn't match any active key, the key you're using is simply gone.
Fix: generate a new API key, save it to your secrets manager or .env file immediately, and update all references.
Cause 2: The key was revoked or deleted
Keys get deleted in several non-obvious ways: an org admin rotates credentials, someone runs a security sweep, or the key was automatically revoked because it was committed to a public GitHub repo (OpenAI scans for leaked keys and auto-revokes them). A revoked key returns the exact same 401 as a wrong key.
Fix: check the keys list on the dashboard. If the key is absent or shown as "Revoked," create a new one. If you committed a key to git history, assume it's compromised regardless of revocation — create a new key and do a git filter-repo purge of the old one.
Cause 3: Project key used on an org-level endpoint
OpenAI introduced project-scoped API keys in 2024. They're prefixed sk-proj- instead of the old sk-. Project keys are bound to a specific project and may not have access to org-level resources. Some endpoints — particularly older ones and admin endpoints — expect an organization-level key or will return 401 for a project key that lacks the right scope.
Fix: if you need broad access, create a key outside of a project context (a "default project" key or a service account key). If you're using a project key intentionally, confirm the endpoint and model you're calling are within that project's scope.
Cause 4: Key not set in the environment correctly
This is by far the most common cause for people who swear the key is correct. The code is reading a different env var than you set, or the var is set in a shell session that's not the one running your process.
Check what your code actually sees:
# Python
python -c "import os; print(repr(os.environ.get('OPENAI_API_KEY')))"
# Node
node -e "console.log(JSON.stringify(process.env.OPENAI_API_KEY))"
If this prints None or undefined, the variable is not in scope for that process. Common causes: using export in one terminal tab but running the app in another; a Docker container not receiving the host env var; a CI runner that doesn't have the secret injected; a .env file that's not being loaded (check that python-dotenv / dotenv is actually called before the OpenAI client initializes).
Fix: confirm with the repr()/JSON.stringify trick above, then trace back to where the variable isn't propagating.
Cause 5: Whitespace or quotes in the key string
A trailing newline, a leading space, or wrapping quotes all produce a 401. This is a common result of:
- Copying a key from a text file that ends with
\n - Setting the env var as
OPENAI_API_KEY="sk-..."in a shell (quotes are fine in the shell, but if you hardcode them in Python asos.environ["OPENAI_API_KEY"] = '"sk-..."', the quotes become part of the string) - Reading from a
.envfile with a library that doesn't strip trailing whitespace
The repr() trick from Cause 4 will reveal this — you'll see 'sk-proj-abc...\n' or '"sk-proj-abc..."' instead of the clean key.
Fix: strip the key at read time: key = os.environ["OPENAI_API_KEY"].strip() and ensure your .env parser handles trailing whitespace.
Cause 6: Wrong organization specified
If your account belongs to multiple OpenAI organizations, you can pass an OpenAI-Organization header (or set organization= on the client) to select which org's billing and limits apply. If you pass an org ID that doesn't match the key's org, you'll get a 401 or 403.
Fix: remove the organization parameter entirely and let OpenAI use the key's default org, or confirm the org ID matches at platform.openai.com/account/organization.
How to verify a key with curl
Before touching application code, confirm the key itself is valid with a single API call:
curl https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY"
A valid key returns HTTP 200 and a JSON list of models. A 401 here means the key is definitively invalid — causes 1–3 apply. A 200 here but 401 in your app almost always means causes 4–6: the key your app is reading is not the same key you tested.
To test a specific key string rather than the env var:
curl https://api.openai.com/v1/models \
-H "Authorization: Bearer sk-proj-YOUR_KEY_HERE"
OpenAI error codes reference
| HTTP status | Error code | Meaning |
|---|---|---|
| 401 | invalid_api_key | Key not recognized — wrong, revoked, or malformed |
| 401 | account_deactivated | The account associated with this key has been deactivated |
| 403 | model_not_found | Key valid, but key lacks access to that model or org |
| 429 | insufficient_quota | Key valid, but billing quota exhausted |
The code field in the JSON error body is what tells you which 401 variant you're dealing with. Log it explicitly — don't just log the HTTP status.
FAQ
Can I reactivate a revoked key? No — once a key is revoked or deleted, it cannot be restored. You must generate a new one.
Is there a way to test a key without making a billed request? Yes — GET /v1/models lists available models and is not a generative call, so it does not consume tokens or incur per-request charges beyond normal API overhead.
My key works in curl but fails in my Python code. What's wrong? Your code is almost certainly reading the key from a different source than your shell env. Add print(repr(openai.api_key)) right before the failing call to see exactly what the client is using.
Related
- OpenAI API 500 Internal Server Error: causes and retry pattern
- Claude API 401 Unauthorized: causes and fixes
- How to reduce your OpenAI API bill
Last updated June 2, 2026. Error codes verified against OpenAI's API reference documentation. OpenAI may change error formats over time — confirm specifics in the current docs before relying on them in production.