[Bug]: Usage → Limits never reports OpenCode Go for OpenCode 2 Console logins#14983

openedOct 3, 2026byBBunBnnuy

What happened

Usage → Limits shows only Codex. My OpenCode Go session/weekly/monthly windows never appear, even though the subscription is active and OpenCode runs locally. The OpenCode Console shows 2% / 36% / 22% used for the same account.

This is the case deferred in #11783 ("if this is still an issue once V2 lands, please reopen or open a fresh PR against the new code"). V2 has landed (#14871), so I'm filing it against the V2 code.

Diagnosis

  • The capability exists and is documented: docs/user/usage.md says "OpenCode Go reports its session, weekly, and monthly allowance when OpenCode runs locally in the environment." No API-key condition is documented. docs/user/providers-opencode.md supports OpenCode 2.0.18+, and #14871 requires 2.0.18+ for V2.
  • readOpenCodeGoUsageLimits resolves credentials from auth.json ("opencode-go" → { type: "api", key }) or OPENCODE_API_KEY only.
  • OpenCode 2 stores a Console login in its SQLite store (opencode.db → credential, integration_id = 'opencode', { type: "oauth", access, metadata: { orgID, ... } }), not in auth.json.
  • With no resolved credential the probe publishes unavailable: { reason: "unsupported" }. The pooled Limits view filters those accounts out, so there is no row and no notice.
  • Not a V2 regression: the credential-resolution logic is unchanged from V1; it is a coverage gap in the existing feature.

Steps to reproduce

  1. OpenCode 2.0.22, signed in through the OpenCode Console. No opencode-go entry in auth.json, no OPENCODE_API_KEY.
  2. T3 Code V2, local OpenCode instance (Server URL empty), provider enabled, refresh provider status.
  3. Open Usage → Limits.
  4. Only Codex appears; the OpenCode Go windows never do.

Version

0.0.46-preview.20261002.2598

Environment

Windows 11 Pro (10.0.26200), x64; OpenCode 2.0.22 (@opencode/cli), local instance.

Evidence

  • Before (installed preview build): Usage → Limits shows only Codex, no OpenCode section and no notice. [screenshot]
  • Expected values, local prototype: Go · Session 98% left, Go · Weekly 64% left, Go · Monthly 78% left. [screenshot — local build of main @ 8ed276c246b6 plus a local patch, not a shipped build]
  • OpenCode Console (Zen/Go): Rolling 2% used, Weekly 36% used, Monthly 22% used. [screenshot] Used% + left% = 100 for all three windows; reset times match (3h 32m / 1d 21h / 21d 18h).
  • With the prototype, server.trace.ndjson shows GET https://opencode.ai/console/api/go/status → 200. That is an internal Console endpoint, not a documented public API.
  • opencode --version = 2.0.22; auth.json contains no opencode-go entry.
  • #11880 — Claude account "silently marked unsupported" in Limits; same failure shape, different provider.
  • #11783 — earlier OpenCode history + Go quota PR, closed pending V2.
  • #12115, #14209 — current implementation reads an API key from auth.json/env.
  • #14871 — V1→V2 migration.

Direction

Is the Console-login configuration intended to be covered by the documented behavior?

  • If yes, which mechanism would you prefer: reading the OpenCode 2 credential database plus the Console status endpoint (internal/undocumented), requiring/documenting an API key for limits, or an upstream/OpenCode-provided endpoint?
  • If no, would you accept a documentation fix stating that Limits requires an API key?

I have a local prototype for the first option but have not opened a PR without direction. Happy to move this to Ideas if Console-login support is out of scope.

Fix applied or workaround

Nothing was changed on the reporting install. Today, limits on main require a Go API key in auth.json or OPENCODE_API_KEY; that is the only working path.

Filed by

deepseek-v4.1-flash (OpenCode) in T3 Code — in-thread machine investigation, not npx t3 triage.

Note

Grok responding on behalf of Julius.

Triage

Thanks for the careful write-up, @BunBnnuy. We confirmed this on main at 8ed276c246. With local OpenCode and a Console login, Usage → Limits shows no Go row and no notice. That's a gap in what the existing probe covers, not a V2 regression.

What the probe reads today: readOpenCodeGoUsageLimits in apps/server/src/provider/Layers/openCodeUsageLimits.ts only runs for an enabled instance with an empty Server URL. It looks for an opencode-go entry of the form { type: "api", key } in $XDG_DATA_HOME/opencode/auth.json (or ~/.local/share/opencode/auth.json, found through USERPROFILE on Windows), and falls back to OPENCODE_API_KEY. If there's no key, or https://opencode.ai/zen/go/v1/usage returns a 403, it reports unavailable: { reason: "unsupported" }. collectLimitNotices in packages/shared/src/usageLimits.ts and the account pool both skip unsupported accounts, so only providers that returned windows show up.

Why a Console login is missed: OpenCode 2 stores new credentials in the credential table of opencode.db and doesn't write them back to auth.json. A Console login is an OAuth token under integration_id = 'opencode', and a pasted Go API key is a separate opencode-go row. The probe reads neither. The API-key path shipped in #12115 (merged), and #14209 (merged) only changed how those snapshots get merged. The earlier PR #11783 was closed without merging because it touched the provider layer during the V2 rewrite, not because Console-login limits were deliberately deferred. The V2 migration (#14871) doesn't change this probe, and #11880 is a separate Limits bug about accounts being labeled by number.

Docs: docs/user/usage.md says local OpenCode reports the session, weekly, and monthly windows, and it doesn't mention needing an API key, so the docs promise more than the probe does.

Possible fixes: there are two separate changes here.

  1. Read an opencode-go API key from the SQLite credential table and keep calling https://opencode.ai/zen/go/v1/usage. That's the #12115 behavior, pointed at the store OpenCode 2 actually uses.
  2. Support Console OAuth logins, which have no Go API key. The only route found is GET https://opencode.ai/console/api/go/status, which is an undocumented Console endpoint. Please hold off on a PR for this one until a maintainer decides whether it's in scope.

Workaround for now: set OPENCODE_API_KEY, or add { "opencode-go": { "type": "api", "key": "..." } } to the auth.json path above. Note that a Zen key without a Go subscription will still stay hidden.

We're leaving this open as a bug. It's still a maintainer decision whether Console logins are in scope, or whether only the SQLite key read is and the docs should say Limits needs a Go API key.

Synced from GitHub

Same on macOS arm64 (Darwin 27), T3 Code desktop 0.0.46-nightly.20261003.2610, OpenCode 2.0.22 running locally, Server URL empty. No auth.json; the provider status cache had usage limits unavailable: unsupported, and Limits showed no OpenCode row.

Workaround that works without a key file: add OPENCODE_API_KEY (a Go API key, marked sensitive) under Settings → Providers → OpenCode → Environment variables. The Go session, weekly and monthly windows appear after a refresh. Might be worth documenting until T3 can read OpenCode 2's credential store.

via t3 triage, Claude Opus 5.5 in Claude Code

Synced from GitHub

One more OpenCode 2 configuration that still shows no Go limits, even with #16605 applied, and that doesn't need the undocumented Console endpoint:

  • OpenCode 2.0.32 with the Console connected through an API key (opencode auth list → OpenCode Console API key stored). In opencode.db that's a credential row with integration_id = 'opencode' and value { "type": "key", ... }. It's not an OAuth token.
  • OpenCode's Console config (GET /console/api/v2/config) lists opencode-go, so OpenCode 2 sends Go traffic through that Console key (it sets opencode-go's integrationID to opencode).
  • The opencode-go row, which was imported from auth.json, holds an older key. GET https://opencode.ai/zen/go/v1/usage returns 401 api_key_expired for that key and 200 with rolling/weekly/monthly for the Console key.

So OpenCode keeps working, but Limits shows "OpenCode Go could not read usage." on main, and still does with #16605.

Fix 1's endpoint (zen/go/v1/usage) and auth shape (a bearer API key) cover this. It doesn't touch OAuth or /console/api/go/status. I have a small follow-up to #16605 ready: try the active Console API key row first, then fall back to the Go key on 401/403, and keep skipping OAuth rows and self-hosted Console keys. Is that within scope for this issue? If so, I'll open it on top of #16605.

Synced from GitHub

Another configuration that still shows no Go limits, and neither open PR covers it. This is macOS arm64, OpenCode 2.0.32 running locally with the Server URL empty, and T3 Code 0.1.1-nightly.20261017.3272.

The credential table has two active rows. I read only their type tags.

integration_idType
opencodeoauth
opencode-gokey

The opencode row came from opencode auth login opencode. There's no auth.json and no OPENCODE_API_KEY. The stored opencode-go key gets 401 authentication_error from GET https://opencode.ai/zen/go/v1/usage, while OpenCode itself keeps working through the Console login.

I called readOpenCodeGoUsageLimits directly against this data with each build.

BuildResult
main at 13aa882c2unsupported, so Limits shows no Go row
#21007unsupported, because it skips OAuth Console rows by design
#16605probeFailed, so Limits shows "OpenCode Go could not read usage."

With #16605, an expired opencode-go row turns a missing Go row into the generic error. Two other machines on this account show that error on main today. I haven't looked at their credentials, but T3 finding an older key there would explain it. A 401 from the usage endpoint could get its own message that tells the user to reconnect OpenCode Go.

A user whose only working credential is a Console OAuth login still has no way to see Go limits in T3. That depends on the /console/api/go/status decision this issue is waiting on.

I can test either PR, or a follow-up, against this setup.

Synced from GitHub

Would it make sense for T3's Go limits probe to use the same account OpenCode uses for Go?

OpenCode 2 stores credentials in SQLite, and a Console login can supply the credential for Go. T3 currently looks for a separate Go API key in the legacy auth file or environment. That means a working Console login can coexist with an expired key that T3 keeps reading.

I'm thinking of this flow, expressed as pseudocode.

text
1account = resolveAccountUsedByOpenCode("opencode-go")
2credential = readCurrentCredential(account)
3usage = fetchGoUsage(existingUsageEndpoint, credential)

The intent would be to follow OpenCode's account selection, keep the existing usage endpoint, and leave credential renewal to OpenCode.

Is that the behavior you'd want here, or should limits remain limited to separate Go API keys? If the direction makes sense, is there a preferred way to resolve the account? I'd also be happy to coordinate with the existing API-key PRs.

Synced from GitHub

Two source-level findings for the scope decision, from a local OpenCode 2.0.32 install (T3 0.1.1-nightly.20261018.3335, Linux).

auth.json is vestigial in OpenCode 2. On the current default branch, the only reader of auth.json is the one-time migration packages/core/src/database/migration/20260805200742_import_legacy_credentials.ts; runtime credential resolution goes through the SQLite credential table (packages/core/src/credential.ts, .../credential/sql.ts). So readOpenCodeGoUsageLimits reads the file OpenCode has abandoned, and skips the store it actually uses. The docs still say otherwise (packages/web/src/content/docs/cli.mdx:142).

OPENCODE_API_KEY is not T3-only. OpenCode reads it in packages/ai/src/providers/opencode.ts (bearer fallback for the opencode provider) and packages/core/src/plugin/provider/opencode.ts (paid-model gating via hasKey), so the workaround above also registers a second Go credential with OpenCode. OPENCODE_AUTH_CONTENT has zero references in OpenCode and T3 honours it ahead of the file, if a T3-scoped knob is preferable.

Re-authing can't self-heal this: after opencode auth login → OpenCode Go, the new key lands in the credential table and nothing is written to auth.json. Here the DB key returns 200 (rolling/weekly/monthly) while the stale auth.json key returns 401 api_key_expired, so Limits stays on the generic banner until the file is edited by hand. Deleting the stale entry instead moves the account from probeFailed to unsupported, i.e. the banner disappears and no Go row appears.

Found via local investigation; DeepSeek V4.1 Flash in T3 Code.

Synced from GitHub

A Console OAuth login works with zen/go/v1/usage itself. No /console/api/go/status needed.

I ran into this myself: "OpenCode Go could not read usage." on every environment, while OpenCode kept working. Same setup as onlydole's report, on two machines: OpenCode 2.0.32 on Windows 11 and on WSL Ubuntu, both local instances with Server URL empty. opencode.db → credential has:

integration_idtypenotes
opencodeoauthmethodID: device, active = 1, from opencode auth login opencode
opencode-gokeyimported from auth.json during the 2.x migration

GET https://opencode.ai/zen/go/v1/usage with each credential as a bearer token, on both machines:

  • opencode-go key: 401 {"code":"api_key_expired", "message":"... Signing in again will not renew this key."}. It's the same key on both machines.
  • opencode OAuth access token: 200 with usage.rolling, usage.weekly, and usage.monthly, and identical values on both machines. Each window also has a status: "ok" field, which the current UsageResponse schema already ignores.

So Console OAuth logins don't depend on the undocumented Console endpoint. The probe could follow onlydole's flow: read the active opencode credential (OAuth or key), then fall back to opencode-go, then to auth.json / OPENCODE_API_KEY. It would keep the existing endpoint and leave refreshing to OpenCode. The stored access tokens here expire about 30 days after login.

Two details for whoever implements this:

  • Fingerprint. Each machine has its own device login and its own access token, so hashing the token won't merge one account across environments the way a Go key hash does. The credential's metadata includes accountID and orgID. Hashing those would merge correctly.
  • Expired keys. A 401 api_key_expired currently shows as the generic "OpenCode Go could not read usage." A specific "reconnect OpenCode Go" message would have pointed me straight at the stale key.

Happy to test a build against this setup.

I hit this on my own machines and dug into it by hand with Claude Opus 5.5 in T3 Code. This isn't an automated sweep; the results above come from my own credentials.

Fresh triage on main at b5a226e49c: this is a usage-reporting bug, not a reported exploitable vulnerability. The current probe still resolves only the legacy Go API key or OPENCODE_API_KEY. The user guide now explicitly documents that a Console sign-in alone does not report limits.

No live reproduction: this Linux environment has no OpenCode credential database, legacy auth file, or OPENCODE_API_KEY, so it cannot exercise the reported subscribed Console account. The October 20 endpoint results in this thread also supersede the earlier assumption that OAuth requires the internal Console endpoint. Leaving this open for maintainer review: implementing Console account selection changes credential resolution, which is outside the automated triage fix scope.

Synced from GitHub

Another configuration for this issue, with no Console OAuth involved: the only credential is a valid Go API key stored in OpenCode 2's SQLite credential table under integration_id = 'opencode-go'.

Environment

  • T3 Code 0.1.3-nightly.20261023.3566, local OpenCode instance, Server URL empty.
  • Linux 6.18.33.2-microsoft-standard-WSL2, x64.
  • OpenCode 2.1.4.
  • ~/.local/share/opencode/opencode.db → credential has one active row: integration_id = 'opencode-go', label = 'OpenCode Go', type = key, active = 1. There is no integration_id = 'opencode' row.
  • The legacy auth.json still contained an older opencode-go key. That key returns 401 api_key_expired; the SQLite key returns 200 with rolling, weekly, and monthly usage.

Behavior

  • With the stale auth.json present: OpenCode: OpenCode Go could not read usage. (generic probeFailed).
  • After deleting auth.json: no OpenCode Go row appears at all (unsupported).

readOpenCodeGoUsageLimits currently reads only integration_id = 'opencode' from SQLite, then falls back to auth.json / OPENCODE_API_KEY. #21007 added the Console API-key case (opencode), but a standalone Go key created through OpenCode Go is stored under opencode-go, so this configuration is still missed.

This looks like the API-key-only part of the triage's possible fix 1, and it does not need the Console OAuth decision. A local patch widening the lookup to IN ('opencode', 'opencode-go') passes the focused provider tests. If both rows can exist, precedence still needs a decision; trying the selected opencode Console credential first and the opencode-go key on 401/403 would preserve #21007's behavior.

Workaround: set the current Go key as OPENCODE_API_KEY in the OpenCode instance's environment variables, then refresh provider status.

No key material is included. (Investigated in-thread with DeepSeek V4.1 Flash in T3 Code.)

Synced from GitHub

Additional local evidence for the OpenCode 2 credential-selection problem:

  • T3 Code 0.1.4-nightly.20261028.3824 uses a local OpenCode instance. Its installed probe skips the active Console OAuth credential. Recent T3 traces show 401 from /zen/go/v1/usage, but do not identify the credential sent.
  • With user authorization, separate read-only requests to that endpoint returned 403 for the API key configured in T3 and for the active Console OAuth token. Neither request included x-opencode-org-id; error bodies were not retained. Go entitlement, effective scopes, SSO and the selected workspace have not been independently verified.
  • OpenCode 2.2.0's usage reader sends x-opencode-org-id for Go. Its test distinguishes that header from Console's x-org-id. Whether including it changes the result for this account has not been tested.

This does not establish why the endpoint returned 403 or contradict the successful OAuth test reported in #23606. That PR has not been run on this installation. I can help with focused tests for workspace selection and how a final 403 is surfaced, once the desired behavior is agreed.

Follow-up: direct-probe correction

A later OAuth request including x-opencode-org-id, made with Python urllib's default user agent, returned 403 with Cloudflare Error 1010 (client signature blocked). The bodies of the earlier 403 responses were not retained, so their precise source was not independently established.

With an explicitly descriptive diagnostic User-Agent, as recommended in Cloudflare's 1010 documentation, the same OAuth credential returned HTTP 200 both with and without x-opencode-org-id. The API key configured in T3 also returned HTTP 200 without the organization header. No credentials, organization identifiers or account usage figures are included here.

Thus the earlier direct 403s cannot be used to infer an OpenCode permission or entitlement failure. The header was not necessary in this particular OAuth comparison, which does not establish behavior for other accounts. T3's earlier 401 is a separate observation; its trace did not identify the credential, and the PR has not been run on this installation.

T3's retained provider snapshot reports OpenCode 2.2.0, probeFailed, and no Go windows. We have not directly tested the older Go key, so whether it produced the earlier T3 401 remains unverified.

Temporary workaround verified on OpenCode 2

For a local OpenCode 2 instance whose Go key is already configured in T3 but is shadowed by an older auth.json entry:

  1. In Settings → Providers → OpenCode → Environment variables, ensure OPENCODE_API_KEY is configured as sensitive with a working key for the intended Go workspace.
  2. Add OPENCODE_AUTH_CONTENT with the literal value {}. If that variable already has another value, do not overwrite it without checking why it was configured.
  3. Refresh the OpenCode provider status, then open Usage → Limits.

In the inspected T3 probe, the empty auth object takes precedence over auth.json, so the Go lookup can use the existing OPENCODE_API_KEY. This does not modify the legacy authentication file. The usage shown belongs to the key's workspace; verify that it is the account you intend to track.

Verified with T3 Nightly 0.1.4-nightly.20261028.3824 and OpenCode 2.2.0: after applying the setting, T3's provider snapshot returned all three Go windows without an unavailable reason. The user confirmed the values, and a user-provided desktop capture shows the three windows and reset countdowns. No screenshot, account identifiers or usage figures are shared here.

This is a version-specific workaround, not a test of #23606 or a general fix. Do not assume the same override is safe for OpenCode 1.x, which can use OPENCODE_AUTH_CONTENT to load credentials.