Skip to content

@ai-sdk/anthropic: ANTHROPIC_BASE_URL convention differs from official Anthropic SDK, breaks under Claude Code / Cursor #15542

Description

@FelixMalfait

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

  1. Detect the bare-host form (https://api.anthropic.com with no path) and append /v1 with a one-time warning.
  2. Switch to the official SDK's convention (default …anthropic.com, prepend /v1/messages internally).

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions