Summary
The same ucode-managed opencode.json succeeds against a Databricks-aware OpenCode fork but returns Forbidden: Invalid Token against published stock OpenCode 1.4.11. The token itself is valid (the fork accepts it on the same wire, with the same opencode.json, in the same shell).
This points at one of two things:
- Stock OpenCode strips or remaps the provider-level
headers.Authorization that ucode writes, so the @ai-sdk/anthropic default x-api-key: <token> reaches the AI Gateway instead — and the gateway's Anthropic translator rejects x-api-key because Databricks bearer tokens are not Anthropic API keys.
- The fork carries header-handling code that stock OpenCode lacks (the fork adds an explicit Databricks provider that injects
Authorization: Bearer <token> deterministically; stock OpenCode may run @ai-sdk/anthropic with its default header pipeline).
Either way, the practical outcome for an end user is the same: ucode configure --agents opencode succeeds, OpenCode launches, and every request 401s.
Reproduction
Using a workspace with AI Gateway v2 enabled (Claude path):
# 1. Configure ucode
DATABRICKS_CONFIG_PROFILE=<profile> \
uv run ucode configure --agents opencode \
--workspaces https://<workspace>
# 2. Confirm the managed opencode.json carries the bearer token at the
# provider level (not just at the model level):
jq '.provider["databricks-anthropic"].options' \
~/.config/ucode/opencode-xdg/opencode/opencode.json
# Expected fields: { baseURL, apiKey, headers: { Authorization: "Bearer ..." } }
# 3. Install stock OpenCode 1.4.11 from npm
bun add -g opencode-ai@1.4.11
which opencode # /<bun-bin>/opencode
# 4. Launch via ucode against stock opencode
ucode opencode run "say hi in 5 words or less"
Observed (stock 1.4.11):
OpenCode exits non-zero. Bun process logs show the AI Gateway returning HTTP 403 to the POST /ai-gateway/anthropic/v1/messages call.
Re-running the same command pointed at a Databricks-aware OpenCode fork (same managed config, same token, same workspace, same shell) succeeds:
OPENCODE_BIN_PATH=/path/to/fork/dist/opencode-darwin-arm64/bin/opencode \
ucode opencode run "say hi in 5 words or less"
# -> "Hi! Five words for you."
The fork carries an explicit Databricks provider that wires Authorization: Bearer deterministically; stock OpenCode runs the AI SDK provider with its default header pipeline.
Hypothesis (most likely)
@ai-sdk/anthropic reads the apiKey option from the provider config and uses it to set x-api-key: <token> on every outbound request, regardless of any headers block. The AI Gateway's /ai-gateway/anthropic translator only accepts Authorization: Bearer <Databricks token> — it rejects x-api-key because that header carries an Anthropic-issued key.
ucode currently writes both:
"options": {
"baseURL": "https://<ws>/ai-gateway/anthropic/v1",
"apiKey": "<databricks-token>",
"headers": { "Authorization": "Bearer <databricks-token>" }
}
…on the assumption that one of the two will land. In the fork the explicit Databricks provider takes precedence and only ships Authorization. In stock OpenCode the @ai-sdk/anthropic provider runs end-to-end and x-api-key wins.
Proposed fix candidates (smallest first)
Option A — drop apiKey, keep only Authorization header
In src/ucode/agents/opencode.py:98–106 and the equivalent gemini block at :109–117:
providers["databricks-anthropic"] = {
"npm": "@ai-sdk/anthropic",
"options": {
"baseURL": opencode_base_urls["anthropic"],
- "apiKey": token,
+ # Don't pass apiKey: @ai-sdk/anthropic uses it to set x-api-key,
+ # which the Databricks AI Gateway rejects (it expects a Databricks
+ # bearer, not an Anthropic-issued API key). The Authorization header
+ # below is what the gateway actually authenticates against.
"headers": auth_headers,
},
"models": dict.fromkeys(anthropic_models, anthropic_model_overlay),
}
This needs verification — @ai-sdk/anthropic may refuse to construct without an apiKey. If so, pass a sentinel ("unused-databricks-uses-bearer") and add a one-line comment.
Option B — wait for a stock OpenCode release that exposes a Databricks provider natively
If Option A doesn't land on stock OpenCode for unrelated reasons (provider validation, header-overwriting upstream), the alternative is ucode pinning to a Databricks-aware OpenCode fork until the upstream merges native Databricks support. That's the path the fork-maintaining team is on today.
Ask
We want to retire the Databricks-aware OpenCode fork and rely on ucode + stock OpenCode. This Forbidden: Invalid Token is the second of two blockers (the first is the missing GPT-5 / Codex provider — filed separately). Could a ucode maintainer:
- Confirm whether the
apiKey + headers.Authorization shape is intended to support stock OpenCode at all, and
- Either apply Option A above (and validate on
opencode-ai@1.4.11) or document the OpenCode version range ucode actually targets in README.md?
Verification evidence
- Token validity confirmed via direct
curl against ${workspace}/ai-gateway/anthropic/v1/messages with Authorization: Bearer <token> — 200 OK.
- Same
opencode.json + same token + same shell → fork succeeds, stock 1.4.11 fails.
- Codex-driven test run (timestamp 2026-05-25 22:38) captured the
Invalid Token failure on opencode-ai@1.4.11; the local fork ran at commit cac7817a7 (feat/databricks-provider).
Summary
The same ucode-managed
opencode.jsonsucceeds against a Databricks-aware OpenCode fork but returnsForbidden: Invalid Tokenagainst published stock OpenCode1.4.11. The token itself is valid (the fork accepts it on the same wire, with the sameopencode.json, in the same shell).This points at one of two things:
headers.Authorizationthatucodewrites, so the@ai-sdk/anthropicdefaultx-api-key: <token>reaches the AI Gateway instead — and the gateway's Anthropic translator rejectsx-api-keybecause Databricks bearer tokens are not Anthropic API keys.Authorization: Bearer <token>deterministically; stock OpenCode may run@ai-sdk/anthropicwith its default header pipeline).Either way, the practical outcome for an end user is the same:
ucode configure --agents opencodesucceeds, OpenCode launches, and every request 401s.Reproduction
Using a workspace with AI Gateway v2 enabled (Claude path):
Observed (stock
1.4.11):OpenCode exits non-zero. Bun process logs show the AI Gateway returning HTTP 403 to the
POST /ai-gateway/anthropic/v1/messagescall.Re-running the same command pointed at a Databricks-aware OpenCode fork (same managed config, same token, same workspace, same shell) succeeds:
The fork carries an explicit Databricks provider that wires
Authorization: Bearerdeterministically; stock OpenCode runs the AI SDK provider with its default header pipeline.Hypothesis (most likely)
@ai-sdk/anthropicreads theapiKeyoption from the provider config and uses it to setx-api-key: <token>on every outbound request, regardless of anyheadersblock. The AI Gateway's/ai-gateway/anthropictranslator only acceptsAuthorization: Bearer <Databricks token>— it rejectsx-api-keybecause that header carries an Anthropic-issued key.ucodecurrently writes both:…on the assumption that one of the two will land. In the fork the explicit Databricks provider takes precedence and only ships
Authorization. In stock OpenCode the@ai-sdk/anthropicprovider runs end-to-end andx-api-keywins.Proposed fix candidates (smallest first)
Option A — drop
apiKey, keep onlyAuthorizationheaderIn
src/ucode/agents/opencode.py:98–106and the equivalent gemini block at:109–117:providers["databricks-anthropic"] = { "npm": "@ai-sdk/anthropic", "options": { "baseURL": opencode_base_urls["anthropic"], - "apiKey": token, + # Don't pass apiKey: @ai-sdk/anthropic uses it to set x-api-key, + # which the Databricks AI Gateway rejects (it expects a Databricks + # bearer, not an Anthropic-issued API key). The Authorization header + # below is what the gateway actually authenticates against. "headers": auth_headers, }, "models": dict.fromkeys(anthropic_models, anthropic_model_overlay), }This needs verification —
@ai-sdk/anthropicmay refuse to construct without anapiKey. If so, pass a sentinel ("unused-databricks-uses-bearer") and add a one-line comment.Option B — wait for a stock OpenCode release that exposes a Databricks provider natively
If Option A doesn't land on stock OpenCode for unrelated reasons (provider validation, header-overwriting upstream), the alternative is
ucodepinning to a Databricks-aware OpenCode fork until the upstream merges native Databricks support. That's the path the fork-maintaining team is on today.Ask
We want to retire the Databricks-aware OpenCode fork and rely on
ucode+ stock OpenCode. ThisForbidden: Invalid Tokenis the second of two blockers (the first is the missing GPT-5 / Codex provider — filed separately). Could aucodemaintainer:apiKey+headers.Authorizationshape is intended to support stock OpenCode at all, andopencode-ai@1.4.11) or document the OpenCode version rangeucodeactually targets inREADME.md?Verification evidence
curlagainst${workspace}/ai-gateway/anthropic/v1/messageswithAuthorization: Bearer <token>— 200 OK.opencode.json+ same token + same shell → fork succeeds, stock 1.4.11 fails.Invalid Tokenfailure onopencode-ai@1.4.11; the local fork ran at commitcac7817a7 (feat/databricks-provider).