Skip to content

fix(opencode-go): treat 403 EntitlementError as not-subscribed and skip silently - #248

Closed
log0u7 wants to merge 3 commits into
slkiser:mainfrom
log0u7:fix/opencode-go-403-entitlement
Closed

fix(opencode-go): treat 403 EntitlementError as not-subscribed and skip silently#248
log0u7 wants to merge 3 commits into
slkiser:mainfrom
log0u7:fix/opencode-go-403-entitlement

Conversation

@log0u7

@log0u7 log0u7 commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Closes #247

Summary

A 403 EntitlementError from the OpenCode Go usage API is a permanent state (the account has no Go subscription), but the plugin kept re-polling it on every refresh and surfaced the raw error in the toast and sidebar indefinitely.

This PR treats that response as a first-class "not subscribed" outcome:

  • lib/opencode-go.ts: detects 403 + EntitlementError (or a "subscription required" body) and returns a notSubscribed result with a stable, redaction-safe message.
  • providers/opencode-go.ts: caches the API key on the first not-subscribed response, short-circuits subsequent fetches (no re-poll until the key changes), and returns a not-attempted result carrying an opencode_go_state: not_subscribed status detail.
  • QuotaProviderResult gains notApplicable: a deliberate no-data outcome that is neither an error nor "not configured". The renderer skips the "Not configured" fallback for it, and the result codec, sanitizer, and clone paths propagate the flag so persistence, cache decode, and exports keep it intact.

Why silent by default

With several configured sources, every unavailable or errored provider adds its own row to the toast: N providers mean N recurring error rows on every idle/interrupt refresh. Deliberate no-data states are permanent (they cannot be resolved from the TUI), so repeating them turns the toast into a wall of recurring errors. Silent-by-default keeps the toast limited to actual data; the state remains observable through statusDetails (/quota status probes).

Users who want the visibility back can set the new documented option:

{
  // one soft intentional-filter line per deliberately no-data provider
  showNotApplicableProviders: true
}

Soft lines use the existing intentional-filter kind, so they do not count as compact-status issues.

Testing

  • Full suite green: 182 files / 2179 tests (vitest, node 22 / pnpm 11 per the repo pins)
  • New tests: 403 EntitlementError detection (and non-EntitlementError 403s stay generic errors), silent skip + short-circuit + key-change invalidation at the provider level, codec propagation, renderer suppression and the opt-in soft line
  • Validated live against a real subscription-less key: no more error toasts on idle/interrupt, other providers unaffected

log0u7 added 3 commits August 28, 2026 13:33
- Detect 403 EntitlementError / subscription-required bodies from the usage API
- Cache the API key and short-circuit re-polls until the key changes
- QuotaProviderResult gains notApplicable for deliberate no-data outcomes
- Renderer skips the Not configured fallback; codec, sanitizer, and clone
  propagate the flag across persistence and export surfaces
- Provider returns notAttempted+notApplicable instead of an error toast
- isQuotaProviderResult whitelists notApplicable and validates its shape
- cloneQuotaProviderResult and sanitizeQuotaProviderResult carry the flag
  so persistence, cache decode, and export paths keep it intact
- Default false: deliberately no-data sources stay fully silent
- true: one soft intentional-filter line per no-data provider in the
  toast and sidebar (does not count as a compact-status issue)
- Documented in docs/readme/configuration.md
- Scales better than per-provider unavailable rows: N configured sources
  would otherwise repeat N error rows on every refresh
@log0u7

log0u7 commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

The CI runs are still in "action_required" because the PR comes from a fork.
Could someone click "Approve and run workflows" in the Checks tab?
Any feedback or review would also be appreciated (fixes #247).

@log0u7

log0u7 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Closing as superseded: issue #247 was fixed upstream by @slkiser in #258 (5b3ffaf + 9d6c124), which implements the same behavior (403 EntitlementError -> notSubscribed, credential fingerprint short-circuit, silent skip). The upstream approach is simpler and landed first. Thanks for the quick integration.

@log0u7 log0u7 closed this Sep 8, 2026
@log0u7
log0u7 deleted the fix/opencode-go-403-entitlement branch September 8, 2026 07:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenCode Go: repeated 403 EntitlementError toasts/sidebar when an API key exists without a subscription

1 participant