Skip to content

auth: expired Go API key error gives no recovery path and misdirects users #56586

Open

Description

@neoscorpi0

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

  1. Subscribe to OpenCode Go and obtain the API key the Go docs describe ("copy your API key").

  2. Configure the Go key and use a opencode-go/<model> (e.g. opencode-go/deepseek-v4.1-flash) normally.

  3. 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 error 2026-10-18 10:52:24.

  4. 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:

  1. 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.

  2. 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/auth before finding this out.

  3. Follow-on misdirection. After re-authenticating, requests failed with:

    Error: Upstream request failed: Insufficient account funds
    

    This 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 a opencode-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:

  1. 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:

  1. 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:

  1. 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.
  2. Distinguish Insufficient account funds from entitlement/routing problems — e.g. tell the user to select a
    Go model, rather than implying they must add credit.
  3. 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

  1. opencode-agent commented on Oct 17, 2026

    @opencode-agent
    Contributor

    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 an opencode-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:

  2. mgajda commented on Oct 18, 2026

    @mgajda

    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 overall
    after endpoint-unavailable.

    Split across two surfaces — 94 as message="stream error", 14 as message="process". Provider was
    opencode-go in 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, so
    the log scatters one problem across three strings. A user scanning the log sees 31 separate lines
    that all mean "re-authenticate".

    Context: #35325, #36582.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions