You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
tui: model list is fetched once at startup and never re-synced — a single 503 during provider boot leaves stale/missing models until restart #60854
The TUI fetches the model list (GET /api/model, GET /api/provider) exactly once at startup. If the per-directory provider instance on the server side is still booting (custom providers/plugins can take tens of seconds — catalog fetch + probes), the request times out after ~5 s with 503, and the TUI never retries:
opening the /models dialog later does not re-fetch (no GET /api/model appears in opencode.log),
/reload fires provider.updated / model.updated events but the list is still not re-fetched,
only quitting and re-launching the TUI re-attempts the fetch.
With a plugin-based provider that supplies models dynamically, the dialog then shows an indefinitely stale list (missing recently added models), while GET /api/model on the same server returns the correct list.
Environment
opencode 2.2.5 (TUI opencode -c connecting to opencode serve --service)
macOS (darwin arm64)
Custom plugin provider (models supplied server-side via provider.transform)
Reproduction
Run opencode serve --service.
Immediately start opencode -c while the server-side provider instance is still booting (plugin setup: catalog fetch + probes).
The server logs GET /api/model http.status=503 (span ≈ 5000 ms) exactly once.
Wait until GET /api/model succeeds (verified via CLI) and open /models in the still-running TUI — no request is sent and the list stays stale.
/reload also does not trigger a re-fetch.
Expected behavior
Retry the model/provider list fetch with backoff after a failure, and/or
re-sync when model.updated / provider.updated events fire, and/or
re-fetch when the model dialog is opened.
Actual behavior
A single 503 is treated as final; the dialog keeps rendering whatever snapshot it had until the TUI process is restarted.
Additional context
Server-side state is correct the whole time (GET /api/model returns the full list once the instance is ready). Related stale-state reports: #36284 (per-directory instance staleness), #50726 (dialog never refreshes after config hot-reload).
Thanks for the detailed report. I tried to reproduce this on 2.2.5 but couldn't confirm it yet.
What I tried: the TUI against a server with a local plugin whose setup() takes 35 s, which is longer than the 5 s the server waits for plugins before GET /api/model returns 503. After setup, the plugin calls ctx.model.reload() every few seconds to fire model.updated. When I opened /models well after the plugin had finished, the dialog still showed the model list. My test setup couldn't make the server's list actually change, though, so I couldn't show the TUI and server disagreeing the way you describe.
From the 2.2.5 code, your explanation is plausible. The TUI retries the initial location sync only 3 times (about 15 s in total). After that, model.updated events for a location that never loaded are ignored, and opening /models doesn't fetch again.
These details would help us reproduce it:
Roughly how long your plugin's setup() takes before the instance is ready.
The opencode.log lines around startup: all GET /api/model and GET /api/provider requests with their status and timing, from both the server and the TUI side if you have them.
In the stale TUI, whether the /models list is empty or shows an older set of models, and whether the prompt footer still shows the agent and model.
A minimal plugin that triggers it, if you can share one, e.g. one that awaits a long sleep in setup() and then adds a model via provider.transform.
Related: #57690 has the same pattern (no retry after a failed startup sync) on the server side, and #60587 reports an empty /model picker with a custom provider on 2.2.3.
Closing this for now, since we couldn't reproduce it and haven't heard back. On 2.2.5 I ran a plugin whose setup() takes 35 s, and the TUI's /models dialog still showed the model list afterwards. My setup couldn't make the server's list change, though, so the test didn't settle whether the TUI goes stale.
If this still happens for you, please reply or open a new issue with:
The opencode.log lines for GET /api/model and GET /api/provider at startup, with their status and timing.
About how long your plugin's setup takes.
What the stale /models dialog shows.
A minimal plugin that triggers it, if you can share one.
With those we can look at it again. Related: #57690, #60587. Thanks for the detailed report.
Activity
opencodejr commentedon Oct 31, 2026
Thanks for the detailed report. I tried to reproduce this on 2.2.5 but couldn't confirm it yet.
What I tried: the TUI against a server with a local plugin whose
setup()takes 35 s, which is longer than the 5 s the server waits for plugins beforeGET /api/modelreturns 503. After setup, the plugin callsctx.model.reload()every few seconds to firemodel.updated. When I opened/modelswell after the plugin had finished, the dialog still showed the model list. My test setup couldn't make the server's list actually change, though, so I couldn't show the TUI and server disagreeing the way you describe.From the 2.2.5 code, your explanation is plausible. The TUI retries the initial location sync only 3 times (about 15 s in total). After that,
model.updatedevents for a location that never loaded are ignored, and opening/modelsdoesn't fetch again.These details would help us reproduce it:
setup()takes before the instance is ready.opencode.loglines around startup: allGET /api/modelandGET /api/providerrequests with their status and timing, from both the server and the TUI side if you have them./modelslist is empty or shows an older set of models, and whether the prompt footer still shows the agent and model.awaits a long sleep insetup()and then adds a model viaprovider.transform.Related: #57690 has the same pattern (no retry after a failed startup sync) on the server side, and #60587 reports an empty
/modelpicker with a custom provider on 2.2.3.opencodejr commentedon Nov 3, 2026
Closing this for now, since we couldn't reproduce it and haven't heard back. On 2.2.5 I ran a plugin whose
setup()takes 35 s, and the TUI's/modelsdialog still showed the model list afterwards. My setup couldn't make the server's list change, though, so the test didn't settle whether the TUI goes stale.If this still happens for you, please reply or open a new issue with:
opencode.loglines forGET /api/modelandGET /api/providerat startup, with their status and timing./modelsdialog shows.With those we can look at it again. Related: #57690, #60587. Thanks for the detailed report.