Repository navigation
Description
Description
Summary
After upgrading an existing install to opencode v2, OpenCode Go stopped working with Missing API key / Invalid credential on every Go model. The root cause was a legacy V1-format provider block (provider.<id> singular key with npm + options) that v2 silently skipped during config normalization, while the modern providers.<id> / OAuth credential path took over. Removing the legacy block alone fixed everything — all 31 Go models work again without any other change.
Environment
- opencode version: 2.0.26 (latest)
- OS: Microsoft Windows NT 10.0.19045.0 (win32 x64)
- Terminal: desktop app (OPENCODE_CLIENT=desktop, xterm-256color)
- Shell: cmd.exe
- Install/channel: latest
- Active plugins: none
Reproduction
- Start from a v1-era config where
opencode.jsoncontains a legacy block:"provider": { "opencode-go": { "npm": "@ai-sdk/anthropic", "options": { "apiKey": ..., "baseURL": "https://opencode.ai/zen/go/v1" }, "models": { ... } } } - Upgrade to v2. Startup logs report the block was skipped:
configuration normalization diagnostic path=$.providers.opencode-go kind=invalid action="skipped malformed recognized value". - Start a session with any
opencode-go/*model → fails withAI.Error: Missing API key(or on desktop connect:Invalid credential/Insufficient account funds). - Delete the legacy
provider.opencode-goblock, keep everything else (including the OAuthopencodecredential in auth.json/database). - Restart → all Go models work. No
providers.opencode-goentry needed.
Expected Behavior
Legacy V1 provider blocks should either be migrated correctly or removed with a clear diagnostic, and the OAuth/credential path used by opencode-go should not be shadowed by a silently-dropped legacy block.
Actual Behavior
v2 silently drops the legacy block (WARN-only), leaving the config in a broken half-migrated state: credentials stored under the OAuth opencode integration instead of opencode-go, so the Go models can never find their key.
Additional Context
- Closely related: [v2] Fresh databases skip legacy auth.json credential import #51342 ([v2] Fresh databases skip legacy auth.json credential import), desktop: "Connect OpenCode Go" runs Console sign-in instead of the Go API-key flow, then reports success and fails with "Insufficient account funds" #50611 / desktop: "Connect OpenCode Go" runs Console sign-in instead of the Go API-key flow, then reports success and fails with "Invalid credential" #52243 (desktop connect runs Console sign-in instead of the Go API-key flow), provider: @ai-sdk/anthropic package returns 401 "Invalid or missing API key" on custom baseURL + authToken in v2.0.21 (works in v1.18.25) #52502 (@ai-sdk/anthropic 401 on custom baseURL in v2.0.21).
- Overriding the legacy block with a hand-written V2
providers.opencode-goentry is NOT what fixes it — v2 flags itkind=invalidand skips it too. The definitive fix was deleting the legacy V1 block so the built-in Go provider + OAuth credential path takes over.
Plugins
No response
OpenCode version
No response
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response
Activity
opencode-agent commentedon Oct 10, 2026
Thanks for the detailed report, and good to hear that removing the block got Go working again.
We'd like to reproduce this, but two parts of the report don't quite fit together:
$.providers.opencode-go(plural). A problem in a legacyprovider.opencode-goblock would be reported at$.provider.opencode-go. So that warning may be about theproviders.opencode-goentry you wrote by hand, not the legacy block.To sort this out, could you please share, in your own words and briefly:
provider.opencode-goblock exactly as it was. Please replace the key withREDACTED, but tell us whether it was a literal key,{env:...}or{file:...}, and include the fullmodelssection.path=) and the exact error you saw, with only the legacy block in the config (no hand-writtenproviders.opencode-go).You can reply here or edit the issue. If you edit it, please also leave a comment saying you've updated it, so we know when you're done.
These existing issues may be related, ordered from most to least likely:
skipped malformed recognized valuewarningprovidersblock ignored in 2.0.16 (fixed)Invalid credential/Insufficient account fundsyindongfang509 commentedon Oct 10, 2026
You're right on both counts — I conflated two different diagnostics, and your second hypothesis is the correct one. Here are the exact facts:
"provider": {
"opencode-go": {
"models": {
"deepseek-v4-flash": {
"name": "DeepSeek V4 Flash",
"reasoning": true,
"variants": {
"high": { "thinking": { "budgetTokens": 8192, "type": "enabled" } },
"low": { "thinking": { "budgetTokens": 2048, "type": "enabled" } },
"max": { "thinking": { "budgetTokens": 16384, "type": "enabled" } },
"medium": { "thinking": { "budgetTokens": 4096, "type": "enabled" } },
"none": { "thinking": { "type": "disabled" } }
}
},
"qwen3.8-max": { /* same shape as above */ }
},
"name": "OpenCode Go",
"npm": "@ai-sdk/anthropic",
"options": {
"apiKey": "REDACTED",
"baseURL": "https://opencode.ai/zen/go/v1"
}
}
}
2. The actual startup diagnostics with only this legacy block present (nothing with path=$.providers.opencode-go, only the singular form):
level=WARN message="configuration normalization diagnostic" path=$.provider.opencode-go.models.deepseek-v4-flash.reasoning kind=unsupported action="omitted unsupported legacy setting"
level=WARN message="configuration normalization diagnostic" path=$.provider.opencode-go.models.qwen3.8-max.reasoning kind=unsupported action="omitted unsupported legacy setting"
And the session failure with the legacy block in place: AI.Error: Missing API key. So you are correct — the block was never skipped. It was accepted with the reasoning field stripped, and shadowed/replaced the built-in Go provider (the skipped malformed recognized value warning I quoted in the original post came from a hand-written providers.opencode-go V2 block I added later, which v2 did reject — I've corrected that in the report).
One extra observation that may matter for your investigation: the overridden provider pinned npm: @ai-sdk/anthropic for all models, including deepseek-v4-flash, which per your endpoint table belongs on /chat/completions (@ai-sdk/openai-compatible). So the shadowing override also got the protocol/route wrong for DeepSeek — possibly compounding with the v2 @ai-sdk/anthropic + custom baseURL regression (#52502).
opencode-agent commentedon Oct 10, 2026
Thanks for the details. I tried this on 2.0.26 with the CLI on Linux, with isolated config and data directories, using your
provider.opencode-goblock exactly but withbaseURLpointed at a local server that logs incoming requests. I ranopencode run --standalone --model opencode-go/deepseek-v4-flash "say hi".What I saw:
...deepseek-v4-flash.reasoning kind=unsupportedone, as you said. The block is migrated and replaces the built-in Go provider.apiKeyfrom your config. Requests to/zen/go/v1/messagessent it asx-api-key; one title request to/zen/go/v1/responsessent it asAuthorization: Bearer. Adding anopencodeentry toauth.jsonmade no difference. OpenCode itself never reportedMissing API key.Invalid API key.for a wrongx-api-key, andMissing API key.only whenx-api-keyis absent (no key, or a Bearer header only). So the request that failed for you seems to have had no key inx-api-key, and I couldn't make that happen.It's expected that a
provider.opencode-goblock in your config replaces the built-in Go provider and its sign-in. Deleting it, as you did, is the right fix: in v2, signing in with OpenCode Console (/connect) also covers Go (see #52374). Your block also forced the Anthropic protocol for DeepSeek and Qwen, which isn't the route those models use.If you think OpenCode is still doing something wrong, these would help:
opencode run --standalone --print-logs --model opencode-go/deepseek-v4-flash "hi"with only the legacy block in place), or only in the desktop app?sk-key in the block was still valid. An old key from before the new Console would be rejected, but withInvalid API key, notMissing API key.Related: #52374 (Go and Console credentials), #52502 (
@ai-sdk/anthropicwith a custombaseURL), #50611 / #52243 / #51689 (desktop "Connect OpenCode Go" flow).yindongfang509 commentedon Oct 10, 2026
Great analysis — I found the exact difference in our reproduction setups, and I think it explains everything.
Your repro used
deepseek-v4-flash, a model defined inside the legacy block. All of my failing sessions used models outside the block (from the built-in Go catalog). From the session database:opencode-go/step-5-preview-freeopencode-go/longcat-2.5-preview-freeopencode-go/step-5-preview-freeopencode-go/deepseek-v4.1-flash(variant: high)All four are chat/completions-route models. Two distinct failures appeared with the legacy block in place:
AI.Error: Missing API keyon the main request, andAI.Error: Model does not support this protocolon others — consistent with these out-of-block models being served through the overridden provider (npm: @ai-sdk/anthropic, baseURL/zen/go/v1), i.e. the wrong protocol route plus no key on the wire.So the hypothesis to test: a model NOT defined in the legacy block's
modelsmap gets the provider's options (apiKey) dropped on the wire, while a model defined inside the block receives it (as you observed). If you can rerun with e.g.opencode run --standalone --model opencode-go/step-5-preview-free "hi"against your logging server, that should reproduceMissing API key.Other details from my side: the failures were on the desktop app, not CLI. The
sk-key in the block was still valid on 10-10 — I verified it directly against the gateway (HTTP 200 on both/chat/completionsand/messages), which matches your point that a wrong key yieldsInvalid API key, notMissing API key. Timeline: the last successful Go call was 2026-09-19; upgrade to 2.0.6 on 09-20; every Go call from 10-08 onward failed until the block was removed.opencode-agent commentedon Oct 10, 2026
Thanks for narrowing that down. I tested your idea on 2.0.26 (CLI, Linux) with your legacy block and the logging server, this time using catalog models that are not in the block:
opencode-go/step-5-preview-freeandopencode-go/deepseek-v4.1-flash.What I saw:
x-api-keyon/zen/go/v1/messages, andAuthorization: Beareron the title request to/zen/go/v1/responses. Models outside the block get the provider'sapiKeythe same way as models inside it, and OpenCode never reportedMissing API key./messagesroute, because the block setsnpm: @ai-sdk/anthropicfor the wholeopencode-goprovider. That most likely explains theModel does not support this protocolerrors you saw. It's expected behaviour when a config block replaces the built-in provider, and removing the block (as you did) is the fix.So the CLI doesn't drop the key here. What I can't test is the Windows desktop app with your Console sign-in connected, which is where you saw it. If you can, it would help to run the same thing with the CLI on your machine, with only the legacy block in place:
and post the error and the log lines around it (with keys redacted). If the CLI works but the desktop app fails with the same config, that points to something specific to the desktop app. Related: #50611 / #52243 / #51689 (desktop Go connection flow) and #52374 (Go and Console credentials).
yindongfang509 commentedon Oct 10, 2026
Thanks for the thorough investigation — but I'd rather not re-reproduce this one. I just got the setup working again after the fix, and deliberately restoring the broken state on a working machine (even temporarily) isn't a trade-off I'm willing to make for a scenario that the CLI doesn't reproduce anyway.
Where things stand, from my side, for the record:
provider.opencode-goblock in place. Symptoms:AI.Error: Missing API keyon the main request andAI.Error: Model does not support this protocolon others, for catalog models (step-5-preview-free,longcat-2.5-preview-free,deepseek-v4.1-flash) that are all chat/completions-route models./messagesroute when the block replaces the built-in provider — which fully explains theModel does not support this protocolerrors.So the actionable takeaways that don't depend on my repro:
omitted unsupported legacy settingWARN for the strippedreasoningfield) is a very quiet way to end up in a broken state. A louder diagnostic like "your provider.opencode-go block replaces the built-in OpenCode Go provider" would have saved users hours.Thanks again for the detailed back-and-forth — it was genuinely useful in narrowing this down.
opencode-agent commentedon Oct 10, 2026
Thanks for the summary, and for all the back-and-forth. It narrowed this down a lot, and it's completely fair not to put the broken setup back.
To restate what's left: you'd like OpenCode to warn clearly when a leftover
provider.opencode-goblock (a legacy one or aprovidersentry) replaces the built-in OpenCode Go provider and its sign-in. Today the only startup message is about the droppedreasoningfield. It would also help if the resulting errors, likeModel does not support this protocolwhen the block's@ai-sdk/anthropicpackage sends chat/completions models to/messages, pointed at the config override as the likely cause. Replacing the built-in provider is intended, but you're right that it happens very quietly, so I've recorded this as a request for clearer diagnostics. Maintainers will consider it.For the record, I couldn't reproduce the
Missing API keyitself with the CLI on 2.0.26: models inside and outside the block both received the key from your config. The desktop app with a Console sign-in is the part that's still untested.Related:
opencode-agent commentedon Oct 16, 2026
Closing this as not planned. As the discussion above confirmed, the config still had a V1
provider.opencode-goblock. V2 migrated that block as a custom provider, and it replaced the built-in OpenCode Go provider, including its sign-in, its credentials, and the protocol each model uses. That custom block is why requests failed, and deleting it was the correct fix.In V2, signing in to OpenCode Console with
/connectalso covers Go, so you don't need anopencode-goentry in your config. Add a provider block only if you deliberately want to override the built-in one.