Repository navigation
Description
Summary
When a stored OpenCode Go API key expires, the TUI error gives no usable recovery path, actively
misstates the fix, and then a follow-on Insufficient account funds error misdirects the user to billing.
Three separate AI assistants (and the user) failed to locate where to create a replacement key from the
error text alone. Access was restored only by signing in with /connect — which the error says will not work.
Environment
- opencode version: 2.0.32
- OS: Linux 7.1.8-arch1-3 (Arch, x86_64), headless
- Terminal: tmux (
TERM_PROGRAM=tmux,TERM=xterm-256color,COLORTERM=truecolor), accessed from Windows Terminal via SSH - Shell: /usr/bin/bash
- Install/channel: latest (
~/.opencode/bin/opencode) - Active plugins: none configured
Reproduction
-
Subscribe to OpenCode Go and obtain the API key the Go docs describe ("copy your API key").
-
Configure the Go key and use a
opencode-go/<model>(e.g.opencode-go/deepseek-v4.1-flash) normally. -
Let the stored key expire (observed lifetime ~47 hours from creation; the key was created automatically
during an upgrade/migration, not by the user's choice).Actual observation: key stored
2026-10-16 11:38:44→ first expiry error2026-10-18 10:52:24. -
Send any prompt.
Expected Behavior
The error should tell the user where to get a replacement key (e.g. a direct link to the relevant Console
page), and should state the recovery options accurately. If a /connect sign-in restores access, the message
must not claim that it will not.
Actual Behavior
Error: This API key has expired. Create a new API key in OpenCode Console and replace it in your client or secret store. Signing in again will not renew this key.
Build · DeepSeek V4.1 Flash · 300ms
Three problems:
-
Misdirects about the fix. The message says "Signing in again will not renew this key." However,
running/connect→ OpenCode and completing the browser sign-in is what actually restored access, and
it has served every request since. The user was told the working fix would not work. -
No recovery path. "Create a new API key in OpenCode Console" gives no link and no location. In the
current Console, keys are not at the workspace level — they live under Keys → Add Service Account →
Add API Key. The user (and three AI assistants) searched Settings, Integrations, Controls and
opencode.ai/authbefore finding this out. -
Follow-on misdirection. After re-authenticating, requests failed with:
Error: Upstream request failed: Insufficient account fundsThis is a billing-sounding error for what is actually a routing/entitlement issue: the request was
being metered against the (empty) OpenCode Console prepaid credit rather than the Go subscription,
until aopencode-go/*model was explicitly selected. Users are pushed toward topping up a balance they
do not need instead of selecting the correct model.
Additional Context
Log evidence (key value redacted; no secret present):
timestamp=2026-10-17T21:52:24.452Z level=ERROR run=<id> message="Failed to drain Session" cause="AI.Error: This API key has expired. Create a new API key in OpenCode Console and replace it in your client or secret store. Signing in again will not renew this key. ..."
timestamp=2026-10-17T22:12:38.311Z level=ERROR run=<id> message="Failed to drain Session" cause="AI.Error: Upstream request failed: Insufficient account funds ..."
Docs / Console divergence. The Go docs still describe the older flow:
- Sign in to the OpenCode Console, subscribe to Go or Go Plus, add your billing details, and copy your API key.
The Console API docs describe the current, different reality:
- Choose a Key name, Permissions, and an optional Expiry date, then click Create key.
So "copy your API key" no longer corresponds to anything the user can see at the workspace level, and the
expiry behaviour ("optional expiry date", i.e. user-chosen) differs from the observed automatic expiry of the
Go key. Worth clarifying in both the docs and the error.
Recovery that worked (for anyone searching this later): run /connect in the TUI, select OpenCode
(the Console sign-in, not "OpenCode Go"), and complete the browser sign-in for the workspace holding the Go
subscription. Then confirm the active model is a opencode-go/* model so billing routes to Go, not Console credit.
Frequency: reproduced consistently for the user until recovery; not intermittent.
Requested improvements:
- Make the error actionable: include the exact Console path (or a deep link) for creating a key, and correct
the claim about signing in again. - Distinguish
Insufficient account fundsfrom entitlement/routing problems — e.g. tell the user to select a
Go model, rather than implying they must add credit. - Reconcile the docs with the Console (service accounts, optional expiry) and, if Go keys genuinely expire
automatically, warn before expiry rather than locking the user out with no notice.
Activity
opencode-agent commentedon Oct 17, 2026
Thanks for the detailed write-up, and for posting the recovery steps that worked for you. They'll help others who hit this.
To restate what you're asking for: when a stored key expires, the error should say accurately how to recover (including that signing in again via
/connect→ OpenCode can get you access back) and where in the Console to create a new key. Also, "Insufficient account funds" shouldn't send Go subscribers to top up credit when the actual problem is that the request isn't using anopencode-go/*model. Both messages come from the OpenCode backend and the app shows them as-is, so this needs changes to the backend messages and/or hints added in the app, plus docs updates. Maintainers will consider it.Related issues, ordered by relevance:
auth logoutmgajda commentedon Oct 18, 2026
Adding scale data from my logs, since this looked like the single largest auth-related failure I hit.
Over 2026-09-24 → 2026-10-16: 108 of 790 ERROR lines (13.7%) were
Upstream request failed: Invalid credential, making it the second most frequent failure overallafter endpoint-unavailable.
Split across two surfaces — 94 as
message="stream error", 14 asmessage="process". Provider wasopencode-goin most cases.What makes it hard to act on is that the message never says which credential or what to do. The
adjacent Go-only auth failures (
An active OpenCode Go subscription is required to use...×12,This Go model requires Global regions×10) are separate messages but the same underlying class, sothe log scatters one problem across three strings. A user scanning the log sees 31 separate lines
that all mean "re-authenticate".
Context: #35325, #36582.