Claude Code Custom ANTHROPIC_BASE_URL Errors: 404s, Auth Conflicts and Fixes
You pointed Claude Code at a gateway with ANTHROPIC_BASE_URL, and now every prompt fails with a model error, Invalid API key, an unexpected login prompt, or a warning about two credentials. Almost every case comes down to one of five config mistakes.
Quick answer
Claude Code appends /v1/messages to ANTHROPIC_BASE_URL on its own, so set it to the bare origin (https://byesu.com, with no /v1 and no trailing slash). Put the gateway token in one variable, normally ANTHROPIC_AUTH_TOKEN, and unset any leftover ANTHROPIC_API_KEY. Claude Code reads shell exports only at startup, so restart it after a change, then run /status to see the base URL and credential it is actually using.
Symptoms and What They Mean
| What you see | Most likely cause | Fix |
|---|---|---|
There's an issue with the selected model (claude-...). It may not exist or you may not have access to it. Run /model to pick a different model. | Base URL ends in /v1, so requests go to /v1/v1/messages and get a 404, or the model ID is wrong | Fix 1, Fix 5 |
Invalid API key · Fix external API key (older versions: Invalid API key · Please run /login) | The ANTHROPIC_API_KEY value was rejected, or contains a character HTTP headers can't carry | Fix 3 |
Please run /login · API Error: 401 Invalid authentication credentials | The gateway rejected the credential. Behind a custom base URL, the text after 401 comes from the gateway | Fix 2, Fix 3 |
A startup warning naming two credential sources and ending in auth may not work as expected (older: Auth conflict: Both a token (SOURCE) and an API key (SOURCE) are set) | A gateway credential and a saved claude.ai login are both active | Fix 2 |
Not logged in · Please run /login, or the claude.ai sign-in screen | No credential reached the session | Fix 4 |
Connection refused — a firewall or proxy may be blocking it (ConnectionRefused) | A leftover ANTHROPIC_BASE_URL points at a proxy that's no longer running, or the host is misspelled | Fix 1 |
Claude Code reports the doubled-path 404 as a model error, so it's easy to miss. A user in anthropics/claude-code#26408 found it by launching with --debug and searching the log under ~/.claude/debug:
[ERROR] API error (attempt 1/11): 404 404 {"error":{"message":"Invalid URL (POST /v1/v1/messages)","type":"invalid_request_error","param":"","code":""}}The body varies by gateway, but /v1/v1/ in the path confirms it.
Why It Happens
- Claude Code builds the path itself. Anthropic's gateway compatibility guide says inference requests post to
/v1/messages(with?beta=true) under yourANTHROPIC_BASE_URL. A base URL that already ends in/v1doubles it. - Each credential variable is sent in a different header, and only one is used.
ANTHROPIC_AUTH_TOKENgoes out asAuthorization: Bearer, andANTHROPIC_API_KEYgoes out asX-Api-Key. The authentication precedence is cloud-provider credentials, thenANTHROPIC_AUTH_TOKEN, thenANTHROPIC_API_KEY, thenapiKeyHelper, thenCLAUDE_CODE_OAUTH_TOKEN, with your/loginsubscription last. If a stale value sits higher in that list, it wins without any warning.
Fix 1: Use the Bare Origin as the Base URL
# Wrong: Claude Code appends /v1/messages → /v1/v1/messages → 404
export ANTHROPIC_BASE_URL="https://byesu.com/v1"
# Right
export ANTHROPIC_BASE_URL="https://byesu.com"Trailing slash: the Anthropic TypeScript SDK collapses https://byesu.com/ + /v1/messages into a single slash, so Claude Code usually tolerates it. Your own curl tests don't get that cleanup and would request //v1/messages, so leave the slash off.
Test the URL and token before opening Claude Code, using the one-token request from Anthropic's gateway setup guide:
curl -sS -w '\n%{http_code}\n' -X POST "$ANTHROPIC_BASE_URL/v1/messages" \
-H "Authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model": "claude-sonnet-5-5", "max_tokens": 1, "messages": [{"role": "user", "content": "."}]}'A body starting with {"id":"msg_ means the URL and token both work. An unknown-model error also confirms both, because the gateway authenticated the request before it looked at the model. A path 404 means the base URL is wrong, and a 401 means the credential is wrong.
Connection refused while curl -I https://api.anthropic.com works usually means a leftover ANTHROPIC_BASE_URL. Remove it from your shell profile and from the settings env block, then open a new terminal.
Fix 2: Use Exactly One Credential Variable
| Variable | Header sent | Notes |
|---|---|---|
ANTHROPIC_AUTH_TOKEN | Authorization: Bearer … | Applies immediately, with no prompt. Anthropic suggests it when a gateway doesn't say which header it expects |
ANTHROPIC_API_KEY | X-Api-Key: … | Interactive mode asks you to approve it once. If you declined it earlier, it is ignored without a prompt; re-enable it under /config → Use custom API key |
env | grep ANTHROPIC # everything your shell passes in
unset ANTHROPIC_API_KEY # bearer-token gateway: drop the other variableMixing them causes confusing 401s: an old ANTHROPIC_AUTH_TOKEN outranks a new ANTHROPIC_API_KEY, and a correct token in the variable whose header the gateway doesn't read never gets accepted.
For the auth-conflict warning, Anthropic's troubleshooting table gives two options: unset the variable to use the saved claude.ai login, or run /logout to keep only the gateway credential. Afterwards, /status should show an Anthropic base URL line and an Auth token or API key line for the credential in use.
Fix 3: Clear "Invalid API key" and 401
Behind a gateway, running /login won't help, because the gateway is the one rejecting the credential. Check these:
- A stale key from the environment. Anthropic's error reference warns that direnv, dotenv plugins and IDE terminals can load an old key from a project
.envwithout you noticing. Runenv | grep ANTHROPICin the terminal you launch from. - Invisible characters. If the message continues past
Fix external API keywith something likeit contains a line break at character 41, the key never left your machine. Re-paste it. - The wrong variable, or a dead token. Switch variables and rerun the curl test, then confirm in the gateway console that the token still exists and is enabled.
General 401 causes are covered in Claude API 401 Authentication Error.
Fix 4: Put the Config Where Claude Code Reads It
The most reliable place for gateway settings is the env block of ~/.claude/settings.json (on Windows, %USERPROFILE%\.claude\settings.json):
{
"env": {
"ANTHROPIC_BASE_URL": "https://byesu.com",
"ANTHROPIC_AUTH_TOKEN": "sk-your-token"
}
}According to the environment variables reference:
- Shell exports are read at startup. After editing
~/.zshrc, open a new terminal and startclaudeagain. - The
envblock is reapplied when you save the file, but removing a variable only takes effect at the next launch. If in doubt, restart. - When both are set, the settings file usually wins over a shell export of the same variable.
Common ways the config goes missing:
- A project's
.claude/settings.json. Don't put a token there, since that file gets committed. Most of itsenvvalues also wait until you trust the folder, so first-run setup can still show the login screen. Use a shell export or~/.claude/settings.jsoninstead. - The VS Code extension. It reads credentials from
claudeCode.environmentVariablesin VS Code's own settings. - Broken JSON. A trailing comma or a
//comment breaks the file and triggers a Settings Error at startup.claude doctorlists what it rejected.
Our Claude Code setup guide also sets "hasCompletedOnboarding": true in ~/.claude.json to skip the claude.ai sign-in screen.
Fix 5: Set Model IDs the Gateway Serves
A correct URL and token can still return There's an issue with the selected model if the model ID doesn't exist on the gateway. The relevant variables, from model configuration:
| Variable | What it controls |
|---|---|
ANTHROPIC_MODEL | The session's model. Overrides the model key in settings files |
ANTHROPIC_DEFAULT_MODEL | The model new sessions start on, used only when no settings file sets model (v2.1.236+) |
ANTHROPIC_DEFAULT_OPUS_MODEL / _SONNET_MODEL | What the opus / sonnet aliases resolve to |
ANTHROPIC_DEFAULT_HAIKU_MODEL | What haiku resolves to; also used for background tasks |
ANTHROPIC_SMALL_FAST_MODEL | Deprecated; use ANTHROPIC_DEFAULT_HAIKU_MODEL |
{
"env": {
"ANTHROPIC_BASE_URL": "https://byesu.com",
"ANTHROPIC_AUTH_TOKEN": "sk-your-token",
"ANTHROPIC_MODEL": "claude-opus-5-5",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-5-5"
}
}Use full model IDs exactly as the gateway lists them. If chat works but background features fail, point ANTHROPIC_DEFAULT_HAIKU_MODEL at a model the gateway does list. CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1 fills the /model picker from the gateway's /v1/models. For model-ID spelling problems, see Claude API 404 model not found.
If You're Using byesu
byesu is an AI API gateway with Anthropic-native and OpenAI-compatible endpoints. One key covers Claude, GPT, Grok and Gemini, billed pay-as-you-go with no subscription. For Claude Code:
- Set
ANTHROPIC_BASE_URL=https://byesu.com, with no/v1and no trailing slash.https://byesu.com/v1is for OpenAI-format clients such as Codex CLI. - Put the token in
ANTHROPIC_AUTH_TOKEN, and copy model IDs such asclaude-opus-5-5orclaude-sonnet-5-5from the console model list.
To get started, create a token and follow the Quick Start. The full walkthrough, including a one-click setup script, is in Connecting Claude Code CLI.
FAQ
Should ANTHROPIC_BASE_URL include /v1?
No. Claude Code appends /v1/messages to ANTHROPIC_BASE_URL itself, so a base URL ending in /v1 produces requests to /v1/v1/messages, which a gateway answers with 404. Use the bare origin, for example https://byesu.com, with no /v1 and no trailing slash.
What is the difference between ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY?
ANTHROPIC_AUTH_TOKEN is sent as an Authorization: Bearer header; ANTHROPIC_API_KEY is sent as an X-Api-Key header and, in interactive mode, must be approved once before it is used. When both are set, Claude Code uses ANTHROPIC_AUTH_TOKEN. Set only the one your gateway expects and unset the other.
Why does Claude Code say Invalid API key and ask me to run /login?
The credential Claude Code sent was rejected, or no usable credential reached the session. Behind a custom base URL, /login does not fix it: check that the right variable is set, that no stale ANTHROPIC_API_KEY is exported in your shell or loaded from a .env file, and run /status to see which credential is active.
Do I need to restart Claude Code after changing environment variables?
For shell exports, yes: Claude Code reads shell variables at startup. Values in the env block of ~/.claude/settings.json are reapplied to a running session when you save the file, but removing a variable only takes effect on the next launch. Restarting is the simplest way to be sure.
Which environment variable sets the model in Claude Code?
ANTHROPIC_MODEL sets the session model and overrides the model setting in settings files. ANTHROPIC_DEFAULT_OPUS_MODEL, ANTHROPIC_DEFAULT_SONNET_MODEL and ANTHROPIC_DEFAULT_HAIKU_MODEL control what the opus, sonnet and haiku aliases resolve to; the haiku one is also used for background tasks. Each needs a full model ID your gateway serves.
