What happened
A Twenty server running inside Claude Code desktop kept getting 404 Not Found from every Anthropic call:
url: 'https://api.anthropic.com/messages'
model: 'claude-sonnet-4-5-20250929'
The 404 isn't the model — it's the path. Claude Code injects ANTHROPIC_BASE_URL=https://api.anthropic.com into child processes. @ai-sdk/anthropic reads that and appends /messages → wrong path.
The mismatch
The two Anthropic SDKs interpret ANTHROPIC_BASE_URL differently.
@anthropic-ai/sdk (src/client.ts):
- default baseURL:
https://api.anthropic.com
- adds version itself:
${baseURL}/v1/messages
@ai-sdk/anthropic (anthropic-provider.ts):
- default baseURL:
https://api.anthropic.com/v1
- appends raw path:
${baseURL}/messages
So ANTHROPIC_BASE_URL=https://api.anthropic.com works with the official SDK and 404s under this one. Setting …/v1 works here but would double up to /v1/v1/messages under the official SDK. Same env var, mutually exclusive meanings.
Why it matters
Anything that injects this env var following Anthropic's own convention silently breaks any app embedding @ai-sdk/anthropic. The user hit it via Claude Code; same trap exists for Cursor's agent tooling, LiteLLM proxy setups that document the bare-host form, and people who configured shells against the official SDK and later adopted ai.
The default https://api.anthropic.com/v1 keeps /messages working without an env var. The break only shows up when something else sets the env.
Reproduce
ANTHROPIC_BASE_URL=https://api.anthropic.com \
ANTHROPIC_API_KEY=sk-ant-… \
node -e "import('@ai-sdk/anthropic').then(async ({anthropic}) => {
const {generateText} = await import('ai');
console.log(await generateText({model: anthropic('claude-sonnet-4-5-20250929'), prompt: 'hi'}));
})"
→ AI_APICallError: Not Found from https://api.anthropic.com/messages. Drop the env var (or append /v1) and it succeeds.
Possible fixes
- Detect the bare-host form (
https://api.anthropic.com with no path) and append /v1 with a one-time warning.
- Switch to the official SDK's convention (default
…anthropic.com, prepend /v1/messages internally).
What happened
A Twenty server running inside Claude Code desktop kept getting
404 Not Foundfrom every Anthropic call:The 404 isn't the model — it's the path. Claude Code injects
ANTHROPIC_BASE_URL=https://api.anthropic.cominto child processes.@ai-sdk/anthropicreads that and appends/messages→ wrong path.The mismatch
The two Anthropic SDKs interpret
ANTHROPIC_BASE_URLdifferently.@anthropic-ai/sdk(src/client.ts):https://api.anthropic.com${baseURL}/v1/messages@ai-sdk/anthropic(anthropic-provider.ts):https://api.anthropic.com/v1${baseURL}/messagesSo
ANTHROPIC_BASE_URL=https://api.anthropic.comworks with the official SDK and 404s under this one. Setting…/v1works here but would double up to/v1/v1/messagesunder the official SDK. Same env var, mutually exclusive meanings.Why it matters
Anything that injects this env var following Anthropic's own convention silently breaks any app embedding
@ai-sdk/anthropic. The user hit it via Claude Code; same trap exists for Cursor's agent tooling, LiteLLM proxy setups that document the bare-host form, and people who configured shells against the official SDK and later adoptedai.The default
https://api.anthropic.com/v1keeps/messagesworking without an env var. The break only shows up when something else sets the env.Reproduce
→
AI_APICallError: Not Foundfromhttps://api.anthropic.com/messages. Drop the env var (or append/v1) and it succeeds.Possible fixes
https://api.anthropic.comwith no path) and append/v1with a one-time warning.…anthropic.com, prepend/v1/messagesinternally).