Short answer
Invalid API key · Please run /login means the endpoint Claude Code sent your request to rejected the credential it was given. When you set ANTHROPIC_BASE_URL, that endpoint is your gateway or proxy, not Anthropic. So the usual cause is a credential mix-up on your machine: the gateway key is in a variable the gateway doesn't read, an old key or a saved claude.ai login is sent instead, or the key isn't one that gateway issued.
Running /login only helps if you want to use your Anthropic account directly. To use a gateway, set the gateway's key as ANTHROPIC_AUTH_TOKEN (sent as Authorization: Bearer), remove any leftover ANTHROPIC_API_KEY, start claude again from the same shell, and run /status to confirm which base URL and credential are active.
If you are setting up TeamoRouter, the two variables are ANTHROPIC_BASE_URL=https://api.teamorouter.com and ANTHROPIC_AUTH_TOKEN=<your TeamoRouter key>. The TeamoRouter section below has the full commands and a key test.
What the error looks like
The wording depends on your Claude Code version and on which credential failed:
Invalid API key · Please run /login
This is the form in anthropics/claude-code#5167, reported on Claude Code 1.0.68. Current versions word it differently. The Claude Code error reference lists this message for a key from ANTHROPIC_API_KEY or an apiKeyHelper script that the API rejected:
Invalid API key · Fix external API key
Two related messages you may see instead:
Not logged in · Please run /login
This one means Claude Code found no usable credential at all. A gateway can also answer with its own 401, which Claude Code shows with the same /login hint. This example comes from a custom-endpoint setup in anthropics/claude-code#7452, with the request ID shortened:
API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"Invalid bearer token"},"request_id":"req_011C..."} · Please run /login
Whichever one you get, the fix starts in the same place: find out which credential Claude Code sent, and to which URL.
No custom base URL at all? Then this page isn't your case. In #5167 the cause was a login that never reached the macOS keychain, often over SSH or inside tmux. Some users in that thread report that running
security unlock-keychain ~/Library/Keychains/login.keychain-dbbefore startingclaudefixes it.
Why it happens with a custom base URL
When several credentials are present, Claude Code uses only one. According to its authentication precedence, it picks the first of these that is present:
- Cloud provider credentials, when
CLAUDE_CODE_USE_BEDROCK,CLAUDE_CODE_USE_VERTEXorCLAUDE_CODE_USE_FOUNDRYis set ANTHROPIC_AUTH_TOKEN, sent asAuthorization: Bearer <token>ANTHROPIC_API_KEY, sent asX-Api-Key. In an interactive session you approve it once; inclaude -pit is always used when set- The output of an
apiKeyHelperscript CLAUDE_CODE_OAUTH_TOKEN- Anthropic profile and federation credentials
- Your saved
/login(Pro, Max, Team or Enterprise subscription)
ANTHROPIC_BASE_URL only changes where requests go. It doesn't change which credential is sent. These are the usual ways the wrong one ends up at your gateway:
- The key is in a variable the gateway doesn't read.
ANTHROPIC_AUTH_TOKENandANTHROPIC_API_KEYput the key in different headers. Anthropic's gateway guide says a credential in the wrong variable arrives in a header the gateway ignores, and the request fails with 401. - Only the base URL is set. With no gateway credential, a saved claude.ai login stays the active credential and is sent to the gateway, which usually can't accept it.
- The key was declined at the approval prompt. A previously declined
ANTHROPIC_API_KEYis ignored without asking again, so Claude Code falls back to your saved login. You can turn it back on under/configwith Use custom API key. - A settings file overrides your shell. When an
envblock in a Claude Code settings file and a shell export set the same variable, the settings file wins. An old key in~/.claude/settings.jsonbeats the one you just exported. - A project
.envloads a stale key. direnv, dotenv shell plugins and IDE terminals can setANTHROPIC_API_KEYfrom a project file without you noticing. - The project settings haven't applied yet. An
envblock in a project's.claude/settings.jsonor.claude/settings.local.jsononly applies after the first-run setup and the folder trust prompt, so the first session can start with no credential and ask you to log in. - The pasted key has a hidden character. A line break or zero-width space copied from a chat or document makes the key invalid. Current versions name the variable and the character position after
Fix external API key. - The key isn't valid on that gateway. It was revoked, mistyped, or it is an Anthropic Console key sent to a gateway that only accepts its own keys.
How to fix it
- See what Claude Code is using. Run
/status. TheAnthropic base URLline should show your gateway. AnAuth tokenorAPI keyline should name the variable you set. If it shows your claude.ai account instead, the gateway credential isn't reaching the session. - List every Anthropic variable in that shell. Run
env | grep ANTHROPIC(PowerShell:Get-ChildItem Env:ANTHROPIC*). Then check theenvblock in~/.claude/settings.jsonand in the project's.claude/settings.local.json. Delete old keys you no longer use. - Put the gateway key in the variable it expects. If the gateway authenticates with a bearer token, or you weren't told which kind, use
ANTHROPIC_AUTH_TOKEN. UseANTHROPIC_API_KEYonly if the gateway readsx-api-key. Keep one of the two, not both. - Retype the key if you pasted it. Copy it again from the gateway's dashboard, not from a chat message or a document.
- Test the gateway without Claude Code. A direct
curlrequest with the same URL and key tells you whether the problem is the key or your Claude Code setup. A 401 there means the gateway itself rejects the key. - Clear the old login if you only use the gateway. If startup warns that two credential sources are set, run
/logoutso that only the gateway credential remains. - Start
claudefrom the same shell. Shell exports don't reach an editor or terminal that was opened from the dock or Start menu. Restart, send a message, and run/statusagain.
Troubleshooting table
| What you see | Likely cause | Fix |
|---|---|---|
Invalid API key right after setting ANTHROPIC_BASE_URL |
The key is in the wrong variable for this gateway | Move it to ANTHROPIC_AUTH_TOKEN, unset ANTHROPIC_API_KEY |
/status shows your claude.ai account, not the gateway key |
No gateway credential reached the session | Export ANTHROPIC_AUTH_TOKEN or put it in ~/.claude/settings.json |
| You exported a new key but the old one is still used | A settings-file env block or a project .env overrides it |
Remove the old value from the settings file or .env |
ANTHROPIC_API_KEY is set but ignored, with no prompt |
You declined it once | /config → Use custom API key |
| Works in a terminal, fails in the IDE | The IDE didn't inherit your shell exports | Put the variables in ~/.claude/settings.json |
Fix external API key followed by a character position |
A hidden character in the pasted key | Retype the key |
401 ... Invalid bearer token |
The gateway rejected the token | Check the key on the gateway's side, or create a new one |
| Asked to log in on the first run in a new project | Project env settings apply only after the trust prompt |
Export the variables in your shell or set them in ~/.claude/settings.json |
If your base URL is TeamoRouter
TeamoRouter is an API gateway with one key for Claude, GPT, Gemini and DeepSeek. Claude runs on the native Anthropic protocol (/v1/messages), so Claude Code only needs a base URL and a key. Billing is pay-per-use with no subscription.
- Create an API key in the TeamoRouter console. It starts with
sk-teamo-. - Set the two variables. On macOS and Linux:
export ANTHROPIC_BASE_URL=https://api.teamorouter.com
export ANTHROPIC_AUTH_TOKEN="your TeamoRouter API key"
unset ANTHROPIC_API_KEY
claude
Leave /v1 off the base URL: Claude Code adds the path itself. On Windows, set the same two variables with setx and reopen the terminal. Model settings and the full Windows commands are in Install and connect Claude Code.
- If it still fails, test the key on its own:
curl https://api.teamorouter.com/v1/models \
-H "Authorization: Bearer sk-teamo-..."
A model list means the key works, so look at your Claude Code variables and settings files again. A 401 means the key itself is wrong: copy it again from the console or create a new one.
Top up from $5. The top-up dialog takes cards. You can also click Pay with crypto and pay with USDT, USDC or ETH from Binance, OKX or any exchange app — the checkout shows which networks your amount supports (BEP20 works from $5). You don't need a wallet extension, and the invoice stays valid for 60 minutes. Step by step: Pay for Claude with USDT.
FAQ
Will running /login fix it?
Only if you want to stop using the gateway and sign in to Anthropic directly. /login saves an Anthropic credential; it doesn't give you a gateway key. While a gateway credential variable is set, Claude Code uses that variable and leaves the saved login unused.
Should I use ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY?
It depends on the header your gateway reads: ANTHROPIC_AUTH_TOKEN sends Authorization: Bearer, ANTHROPIC_API_KEY sends x-api-key. Anthropic's guide suggests ANTHROPIC_AUTH_TOKEN when you aren't sure. TeamoRouter's Claude Code guide uses ANTHROPIC_AUTH_TOKEN.
Why does claude -p fail when the interactive session works?
In -p mode, ANTHROPIC_API_KEY is always used when it's set. An interactive session may be ignoring a key you declined and using another credential. Make sure the shell or CI job that runs claude -p has only the gateway credential.
My key works in curl but Claude Code still asks me to log in. Why?
A reachable base URL isn't a credential. Claude Code needs the key in one of its credential variables, set somewhere it reads before startup: a shell export, the env block in ~/.claude/settings.json, or managed settings.