Repository navigation
Description
Summary
A custom provider configured with package: "aisdk:@ai-sdk/anthropic", a custom settings.baseURL, and settings.authToken fails every request with HTTP 401: Invalid or missing API key on opencode v2.0.21. The identical opencode.json provider definition works correctly against the same endpoint on opencode v1.18.25. A sibling provider on the same gateway using @ai-sdk/openai-compatible with the same credential works fine on both versions, isolating the regression to the Anthropic-native package's v2 request path.
Environment
- opencode version: 2.0.21 (failing) / 1.18.25 (working) — both installed locally, same machine
- OS: Darwin 25.6.0 (macOS, arm64)
- Terminal: Unavailable (environment variables not set in this context)
- Shell: /opt/homebrew/bin/fish
- Install/channel: latest (v2.0.21 bundled by a desktop client; v1.18.25 via Homebrew)
- Active plugins:
-opencode.browser, a local agent-tool plugin,opencode-agent-skills@0.6.5
Reproduction
- Configure a custom Anthropic-compatible provider in
opencode.json:"providers": { "my-anthropic-gateway": { "name": "My Anthropic Gateway", "package": "aisdk:@ai-sdk/anthropic", "settings": { "baseURL": "https://gateway.example.com/v1", "authToken": "{env:GATEWAY_API_KEY}" }, "models": { "claude-model": { "modelID": "claude-model", "name": "Claude Model", "capabilities": { "tools": true, "input": ["text"], "output": ["text"] }, "limit": { "context": 1000000, "output": 64000 } } } } }
- Verify the key works directly against the gateway's
/v1/messagesendpoint withcurl -H "Authorization: Bearer $GATEWAY_API_KEY"→ returns 200. - Run a session on opencode v1.18.25 using
my-anthropic-gateway/claude-model→ succeeds consistently. - Run a session on opencode v2.0.21 using the same config, same env var, same model → every request fails with:
AI.Error.Authentication: Provider request failed with HTTP 401: { "type": "https://httpstatuses.com/401", "title": "Unauthorized", "detail": ["Invalid or missing API key"], "status": 401, "instance": "/v1/messages" }
Expected Behavior
v2.0.21 should send the same Authorization: Bearer <authToken> header to /v1/messages that v1.18.25 sends, and the gateway should accept it (as proven by direct curl and by v1.18.25 working).
Actual Behavior
Every request from v2.0.21 to the custom Anthropic provider's /v1/messages endpoint is rejected with 401 "Invalid or missing API key", even though:
- The same API key/env var is confirmed valid via direct
curlagainst the same endpoint. - The same key works through a sibling
@ai-sdk/openai-compatibleprovider pointed at the same gateway (different endpoint path) under the same v2.0.21 process. - The credential stored by the client matches the live environment variable byte-for-byte (verified via hash comparison).
This strongly suggests the @ai-sdk/anthropic provider package in v2.0.21, when given a custom baseURL + authToken, fails to attach the Authorization: Bearer header correctly (or attaches it malformed/empty) on the outbound request, while v1.18.25's equivalent code path does it correctly.
Additional Context
- Confirmed via server logs: 100% of
@ai-sdk/anthropic-routed requests under the v2.0.21 process fail with this 401; 100% of requests to the same endpoint/key under v1.18.25 sessions succeed. - The sibling
@ai-sdk/openai-compatibleprovider (same gateway, same API key, different package/endpoint) has zero failures under the same v2.0.21 process in the same time window — ruling out network, key, or gateway-side causes. - Direct
curlreproduction against the gateway withAuthorization: Bearer <key>returns 200 reliably; with bothAuthorizationandx-api-keyheaders it's also 200; with onlyx-api-keyit 401s — meaning the gateway strictly expectsAuthorization: Bearerfor this key, matching the documented behavior ofauthTokenin@ai-sdk/anthropic'sAnthropicProviderSettings. - No config changes were made between the working v1.18.25 run and the failing v2.0.21 run — same
opencode.json, same environment, same machine. - Workaround: none available for this specific model, since it is only exposed via the Anthropic Messages API on our gateway (not available through the OpenAI-compatible chat-completions route).
Activity
github-actions commentedon Oct 1, 2026
This issue might be a duplicate of existing issues. Please check:
@ai-sdk/anthropicprovider drops the API key at runtime with a custombaseURL, resulting in a 401.valleedelisle commentedon Oct 1, 2026
Update: narrower root cause + confirmed workaround
Follow-up after further isolation (same environment as the original report).
Corrected root cause: this is not a blanket "
authTokenis broken in v2.0.21" regression. It is specific to how an implicitsettings.authTokenis resolved when a credential for the provider also exists in the client's credential store (created via a "connect"/UI flow rather than purely from the static config file).settings.apiKeyand an explicitheaders.Authorization: Bearer {env:...}override, works correctly on the same v2.0.21 build, same gateway, same key.settings.authToken(no explicitheadersoverride), reliably produced401 Invalid or missing API keyat/v1/messages— even though the same key is valid per directcurland matches byte-for-byte (hash-verified) what's stored for the provider.@ai-sdk/anthropic's request construction, explicitoptions.headers/providerheadersare spread last, after whateverapiKey/authTokenresolution produces — so an explicitAuthorizationheader always wins regardless of internal resolution. That's why the teammate's config is unaffected while ours wasn't.headers: { "Authorization": "Bearer {env:API_KEY}" }alongsidesettings.apiKey(orauthToken) fixes it immediately — verified via a live end-to-end session with no further 401s.This points suspicion specifically at how the v2 credential-store layer injects a stored "connect"-flow credential into
@ai-sdk/anthropic's auth option (possibly defaulting it intoapiKey/x-api-keyinstead of honoring a config-declaredauthToken, or otherwise failing to carryauthTokenthrough when a stored credential of generic shape{type: "key", key: ...}exists for the provider) — rather than a wholesale break ofauthTokensupport in the package itself, since static-config-only usage (no stored credential) continues to work fine on both versions.Happy to provide more targeted logs/repro around the credential-store injection path if useful for triage.
opencodejr commentedon Oct 28, 2026
Thanks for the detailed report. I could reproduce this on 2.0.21, and it still happens on the latest
dev(891a020bc).The 401 only appears when the same key is also stored as a credential for the provider, which matches what you described about the client's stored credential:
aisdk:@ai-sdk/anthropic, custombaseURL,authToken: "{env:GATEWAY_API_KEY}") against a local mock gateway that only acceptsAuthorization: Bearer,opencode runwith no stored credential sendsAuthorization: Bearer <key>and works.opencode auth login my-anthropic-gateway --method key, the request goes out with onlyx-api-key: <key>, noAuthorizationheader, and fails withHTTP 401 ... Invalid or missing API key.It looks like a stored key credential replaces the configured
authTokenand is sent as an API key (x-api-key) instead of a Bearer token. Until this is looked at, removing the stored credential for that provider (opencode auth logout) and relying onsettings.authTokenalone should avoid the 401. That worked in my test.The script below reproduces it end to end.
Reproduction script (repro.sh)
Run it:
bash repro.sh