Skip to content

[Bug]: OpenCode model missing at startup, shows Unavailable until manual provider refresh #15994

Open

Description

@ignaciorasetti

What happened

At startup the saved model opencode/muse-spark-1.3-contributor-free shows in the model picker with an Unavailable badge. After Settings, Providers, Refresh providers, the same slug resolves to Muse Spark 1.3 Free with no badge.

Steps to reproduce

  1. Set model to opencode/muse-spark-1.3-contributor-free.
  2. Close T3 Code completely.
  3. Open T3 Code again.
  4. Open model picker. The saved model shows as opencode/muse-spark-1.3-contributor-free with an Unavailable badge.
  5. Go to Settings, Providers, run Refresh providers.
  6. Open model picker again. The same slug now resolves to Muse Spark 1.3 Free with no badge.

Expected behavior

Startup catalog should include the same OpenCode models as manual refresh, or the UI should show a loading state instead of Unavailable while the first probe is still running.

Actual behavior

At startup the saved model is kept as a row with isUnavailable:true. After manual refresh it resolves normally. Screenshot attached.

Impact

Minor bug or occasional failure

Version or commit

main @ cf3e714b0f58e29c8fa8660db50d2187e3263b65 (2026-10-05). Desktop app is T3 Code Nightly.

Environment

Windows, T3 Code Nightly, OpenCode driver 2.0.22, provider opencode.

Diagnosis, from code read

  • apps/web/src/modelSelection.ts:93-112 appends the Unavailable row when the saved opencode slug is absent from raw models.
  • apps/web/src/components/chat/ModelListRow.tsx:80-84 renders the badge.
  • Startup returns a pending OpenCode snapshot with models=[], in apps/server/src/provider/Layers/OpenCodeProvider.ts:336-379. The real checkProvider runs forked in background with errors ignored, in apps/server/src/provider/makeManagedServerProvider.ts:281-284.
  • Boot hydrates UI from per instance disk cache, in apps/server/src/provider/Layers/ProviderRegistry.ts:351-425. A cache written before the new model existed misses the slug.
  • OpenCode 2 loads its catalog lazily and retries empty model.list for up to 5s, in apps/server/src/provider/Layers/OpenCodeProvider.ts:389-411. lastLoaded is memory only, so a restart loses it. Failed or empty probes retain old rows, in ProviderRegistry.ts:118-191.
  • Manual refresh in apps/server/src/ws.ts:2263-2304 runs modelManifest.forceRefresh, invalidateCaches, fresh maintenance, then providerRegistry.refresh(). That hits a warm server, lists 465 models, persists new cache in ProviderRegistry.ts:448-468.

Likely cause is cold start racing a lazy OpenCode 2 catalog plus stale disk cache, not a filter. No free versus paid filtering exists in the OpenCode path.

What I checked locally:

orchestrator_capabilities now: opencode has 465 models, includes muse-spark-1.3-contributor-free
provider status cache after refresh lists 465 models and contains
  slug "opencode/muse-spark-1.3-contributor-free"
  name "Muse Spark 1.3 Free"

Server trace holds spans only. No muse-spark or refreshProviders strings found there.

Workaround

Run Settings, Providers, Refresh providers once after startup.

Activity

  1. juliusmarminge commented on Oct 5, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks for the careful code read and the local checks, @ignaciorasetti. Your diagnosis holds up on current main (cf3e714b0f). This looks like a startup catalog race, not a free-vs-paid filter.

    What I found

    • The Unavailable row comes from the client. appendUnavailableDynamicModelSelection in apps/web/src/modelSelection.ts adds the saved slug with isUnavailable: true whenever it's missing from the OpenCode instance's model list, and ModelListRow renders the badge. The server never sends that flag.
    • Boot uses the disk cache, and OpenCode doesn't probe again on its own. ProviderRegistryLive hydrates from the per-instance cache. The live snapshot starts as makePendingOpenCodeProvider (installed: false, status: "warning", no models), and the real checkProvider is forked with its failure ignored (makeManagedServerProvider.ts). OpenCodeDriver.ts sets refreshOnInterval: false and checkProviderOnSettingsChange: () => false.
    • The first non-empty list wins. makeOpenCode2ModelLoader retries an empty model.list for up to 5s, then keeps the first non-empty list, and lastLoaded lives only in memory. Manual refresh (serverRefreshProviders with refreshModels: true) hits an already-warm OpenCode 2 server, which is why the slug then resolves to Muse Spark 1.3 Free.
    • One small correction: an empty or failed probe doesn't always keep the old rows. shouldRetainMissingProviderModels keeps them only for the pending boot snapshot and for a failed probe (status: "error"). A completed warning with an empty list, or a ready probe with a partial list, replaces the cache. Since nothing schedules another check, a partial first list sticks.

    A useful next check: after one manual refresh, cold-start again. If the badge comes back, the startup probe is overwriting a good cache with a partial list. If it stays resolved until OpenCode adds another model, the disk cache was just stale and the boot probe never replaced it.

    Related open PRs, neither merged: #15202 waits for integration.list (plugin activation) before trusting model.list, which is closer if this model only appears after the opencode provider activates. #15510 waits for model.updated and mainly addresses display names, so it probably wouldn't explain a missing slug.

    Workaround: as you noted, run Refresh providers once after startup.

    Likely fix area

    • makeOpenCode2ModelLoader in apps/server/src/provider/Layers/OpenCodeProvider.ts. One option is to wait for the catalog to settle (as fix(opencode): wait for provider activation before caching models #15202 does) before treating a list as complete.
    • OpenCodeDriver.ts / ProviderRegistry.ts. Another option is to schedule a follow-up probe after boot, or to avoid replacing a cached list with a partial one.
    • apps/web/src/modelSelection.ts. A third option is to show a loading state rather than Unavailable while the first probe is still pending.

    A maintainer will decide on the fix direction.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 5, 2026
  3. ignaciorasetti commented on Oct 5, 2026

    @ignaciorasetti
    Author

    Follow-up on the next check you suggested.

    I checked that if I refresh and cold start again, the \Unavailable\ badge on \opencode/muse-spark-1.3-contributor-free\ comes back. So this is not a one time stale cache. Every startup reproduces it.

    One more detail: on my last start I had to run Refresh providers twice in a row before the slug resolved. The first refresh did not bring it back.

  4. Narayan201120 commented on Oct 12, 2026

    @Narayan201120

    @juliusmarminge this still reproduces on my machine, on nightly, so I do not think the race is behind us.

    What I am seeing at startup, from the thread details panel banner:

    OpenCode provider status
    OpenCode 2 is running, but it did not list any models yet.
    

    and the composer model picker shows the saved model with an Unavailable badge. Same shape as the original report: the server is up, the catalog is empty, and the slug only resolves after a manual refresh. One difference from the original report is that mine is an opencode-go/* slug (opencode-go/glm-5.3) rather than opencode/muse-spark-1.3-contributor-free, so this looks like it is not limited to the opencode provider prefix or to a free tier.

    Still on OpenCode 2, Windows, nightly. I have not isolated whether the banner and the badge are the same empty-list read or two different ones, the banner coming from the provider status check and the badge from the model catalog.

    I do not have the log handles to say whether makeOpenCode2ModelLoader is still keeping an empty first list after its retry window, or whether this is the stale disk cache hydrating the UI before the probe lands. @ignaciorasetti had to refresh twice in a row on one start, which also fits either.

    Screenshot to follow.

    Image

    No code from me on this one yet.

  5. razzeee commented on Oct 16, 2026

    @razzeee
    Contributor

    I also have this from time to time and I just had a colleague that ran into it.

  6. Narayan201120 commented on Oct 16, 2026

    @Narayan201120

    6. I also have this from time to time and I just had a colleague that ran into it.

    try refreshing from providers section in the settings. works for me. else restart the app

  7. shunkakinoki commented on Oct 20, 2026

    @shunkakinoki

    Same symptom on 0.1.1-nightly.20261019.3360 with OpenCode 2.0.32 on Linux, as the "Limited" warning: "OpenCode 2 is running, but it did not list any models yet."

    Cause found in provider-opencode:

    • makeOpenCode2ModelLoader repeats model.list until it gets a non-empty list, with timeoutOption("5 seconds"). That five seconds runs inside openCode2Server.withConnection, so it includes spawning and verifying a cold opencode serve. The server is closed again after OPENCODE_SERVER_IDLE_TTL (30s), so most health checks start cold.
    • A freshly spawned server answers /api/model with {"code":"service_starting"} and lists models about 2.3s after spawn on an idle host. Measured on the server T3 spawned itself. A loaded host goes past 5s.
    • On timeout, the loader returns lastLoaded, which is [] for a new instance. checkOpenCode2 then reports warning with zero models, and that stays until the next providerHealthRefreshInterval (5 min on balanced). A manual server.refreshProviders returns ready with 531 models.

    Possible fixes: start the 5s budget after the server is verified, keep the previous snapshot's models instead of replacing them with [], or keep the server warm between health checks.

  8. beci commented on Oct 20, 2026

    @beci

    Same issue on Windows, adding a data point from the server trace.

    T3 Code Nightly 0.1.1-nightly.20261020.3399, OpenCode 2.0.32, Windows 11, managed server (no serverUrl). It happens on the first launch after a reboot or app update.

    checkOpenCode2 spans from server.trace.ndjson, all on the same day:

    Start startServerAttempt GET /api/model checkOpenCode2 Result
    10:28:47 server already warm 1751 ms 4617 ms models loaded
    10:30:50 (restart after update) 1975 ms interrupted after 3027 ms 5012 ms no models
    13:11:10 2529 ms 1456 ms, then 203 ms 5019 ms 52 models, ended right at the limit

    In the failing run, the spawn used about 2 s of the 5 s budget. The first /api/model read was still running when the timeout interrupted it. After that, no checkOpenCode2 ran again until the next app restart about 2.5 hours later, even though several ws.rpc.server.refreshProviders calls ran in between. Taking the server spawn out of the timed region, as discussed above, would have prevented both the failure and the near miss.

  9. t3dotgg commented on Oct 21, 2026

    @t3dotgg
    Member

    Note

    🤖 Claude Opus 5.5 responding on behalf of Theo

    Thanks for the report. One part of this is fixed on main in #16448. Please test on the nightly built from main on 2026-10-21, or on the next stable release. One part is still open: A cold catalog that stays empty through the five-second limit can still omit the saved model. If that part still matters to you, please open a new issue for that part only.

  10. mynameistito commented on Oct 21, 2026

    @mynameistito

    Another reproduction of the empty OpenCode 2 startup catalog:

    What happened

    On every T3 Code startup, OpenCode 2 is reported as running but with no models listed. Refreshing provider status (or toggling the OpenCode provider off and on) makes the models appear.

    Diagnosis and evidence

    The local server.trace.ndjson matches the cold-start timeout described in this issue. In the failing checkOpenCode2 run, starting the managed OpenCode server took about 3.46 seconds. The subsequent GET /api/model was interrupted after about 1.57 seconds, and the provider check completed at about the five-second limit without models. A later provider refresh successfully loaded the catalog.

    This appears to be the remaining empty-catalog-through-timeout case noted in the Oct 21 triage comment. The catalog-settling fix in #16448 addresses an early partial nonempty result; this trace instead shows the model request still in flight when the five-second check is interrupted.

    Reproduction

    1. Start T3 Code and wait for the OpenCode 2 provider status check.
    2. On this install, the status says OpenCode 2 is running but has not listed models.
    3. Refresh provider status or toggle the provider off and on; models then appear.
    4. Repeat after restarting T3 Code; the startup behavior recurs.

    Environment

    • T3 Code desktop nightly: 0.1.2-nightly.20261021.3486
    • OS: Windows x64, build 10.0.26300
    • Node: v26.8.2
    • OpenCode: 2.x; exact installed CLI version not recorded in the triage context
    • T3 triage CLI: 0.1.1 (launched with bunx t3 triage; this is not the desktop app version)

    Related work

    PR #16448 merged on Oct 19 and settles model catalogs before caching. The Oct 21 triage note on this issue says a cold catalog that remains empty through the five-second limit may still omit models.

    Evidence summarized from local server trace; user home path and credentials omitted.

    Prepared by Codex, GPT-6, via T3 Code triage.

  11. t3dotgg commented on Oct 22, 2026

    @t3dotgg
    Member

    Note

    🤖 Claude Opus 5.5 responding on behalf of Theo

    Reopening: a second user still sees the empty OpenCode model list at startup on nightly 0.1.2-nightly.20261021.3486, which includes #16448. The 5-second startup check can end before the model list has loaded.

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

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions