Skip to content

cli: unset root model resolves to an unavailable opencode-go model, breaking every agent without an explicit model #62910

Open

Description

@627-hub

Summary

With no root model configured, OpenCode v2.2.6 resolves the implicit default model to opencode-go/hy4 whenever OPENCODE_API_KEY is present in the environment — even when that key has no active Go subscription. hy4 is the newest model in the catalog (released 2026-11-04), so release-date fallback ordering selects it. Every agent that has no explicit model (plan, general, explore, title, summary, compaction) then fails on every request:

> general · hy4
Error: An active OpenCode Go subscription is required to use Go models.

Nothing in config or api agent.list warns that the resolved default is unusable. The only signal is the failure at request time.

Environment

  • opencode version: 2.2.6
  • OS: Darwin 27.2.0 arm64 (macOS 27.2)
  • Terminal: Apple Terminal, TERM=xterm-256color, TERM_PROGRAM=Apple_Terminal, COLORTERM=truecolor
  • Shell: /bin/zsh
  • Install/channel: npm global, @opencode/cli@2.2.6, Node v22.23.1
  • Active plugins: local superpowers plugin directory (reproduced with {"plugins":[]} as well, so the plugin is not involved)

Reproduction

Minimal, in an empty directory with no opencode.json, no .opencode/, no project config:

  1. Ensure OPENCODE_API_KEY is set to a key whose Go subscription is expired or absent, and that no root model is configured.
  2. Run:
    cd "$(mktemp -d)"
    opencode run --agent general "hi"
  3. Observe > general · hy4 followed by Error: An active OpenCode Go subscription is required to use Go models.

The same failure occurs for plan, explore, title, and summary. Reproduced 3/3.

Expected Behavior

  • Implicit default resolution should not select a model from a provider whose credentials cannot actually serve requests.
  • If the resolved default is unusable, api agent.list / the TUI should show it as unresolved (or pick a working model), rather than silently reporting (inherit).
  • An agent without model should fall back to an enabled, authorized model, or fail with an error that names the cause (no usable default) rather than a provider-specific subscription message.

Actual Behavior

opencode-go/hy4 is selected and every inheriting agent fails.

Isolation (this narrows the trigger to one env var)

All runs use --standalone, an empty temp directory, and no project config. Only the environment differs:

OPENCODE_API_KEY OPENCODE_CONSOLE_TOKEN Resolved model Result
unset unset opencode-go/iceman-free works
unset set opencode-go/iceman-free works
x (garbage) unset opencode-go/iceman-free fails later with Reconnect OpenCode Console to continue.
"" (empty string) unset opencode-go/iceman-free works
real key, expired subscription unset opencode-go/hy4 fails: subscription required

Two things stand out:

  1. A real-but-expired key is treated worse than a garbage key. Garbage x falls back to iceman-free and fails with a reconnect prompt; a syntactically valid key that merely lacks an active subscription is silently promoted to becoming the default model for every unconfigured agent.
  2. The default changes with credential validity. The resolution result differs between "no key" and "key with expired subscription", which means availability is being derived from key presence rather than from an authorized subscription.

The background service differs from --standalone in the same way: the running service process has OPENCODE_API_KEY in its environment, so opencode run --agent general (no --standalone) fails identically, while --standalone with the variable unset works.

Additional Context

Fallback ordering is affected, not just this one model

Disabling hy4 does not solve it; the next newest models are also unusable:

{"providers":{"opencode-go":{"models":{"hy4":{"disabled":true}}}}}

then resolves to crouton-alpha-free, which fails with This model is not available in your country.

Disabling hy4 plus the three -free models resolves to kimi-k3.1-pro, which fails with the same subscription error.

So release-date ordering keeps walking down a list of catalog entries that are not callable in this environment. Two of the failures are not "unavailable model" errors at all but geo-restriction errors, which suggests availability checks do not consider region.

Disabling the whole provider does not work

Trying to take the provider out of the running entirely had no effect:

{"providers":{"opencode-go":{"disabled":true}}}

still resolves to opencode-go/hy4. The schema for encoded providers (Config.ProviderEncoded) lists only canonical, name, env, package, compatibility, settings, headers, body, models, so a provider-level disabled key is not part of the documented shape and is silently ignored. Only per-model disabled has an effect.

Workaround

Setting an explicit root model avoids the fallback path entirely:

{"model":"<provider>/<model>"}

Verified: with that set, general resolves to the configured model and runs. Removing it restores the failure. Pinning model on each individual agent also works but does not scale.

Related

Activity

  1. opencodejr commented on Nov 9, 2026

    @opencodejr

    Thanks for the very thorough write-up and the environment matrix. They make the cause easy to follow.

    In short, you'd like the implicit default model (when no root model is set) to skip models your credentials can't actually use, such as Go models without an active subscription or models blocked in your region. You'd also like agent.list and the TUI to show when the resolved default isn't usable.

    From the code, v2.2.6 picks the default as the newest enabled text model by release date. Paid OpenCode models are enabled whenever a key is present (OPENCODE_API_KEY or a Console connection). The client doesn't check subscription status or region, so with your key set, opencode-go/hy4 wins by release date. Since that is how the picker was built, I've filed this as a feature request rather than a bug. The maintainers will consider it.

    Until then:

    • A root model in your config avoids the fallback entirely, as you found.
    • providers.<id>.disabled isn't a supported key, which is why it had no effect. Provider-level disabling goes through policies. I've checked this in the code but haven't run it:
      {
        "policies": [
          { "action": "provider.use", "resource": "opencode-go", "effect": "deny" }
        ]
      }
      The older "disabled_providers": ["opencode-go"] is converted into the same policy.

    Related issues:

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