Skip to content

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

Closed as not planned

Description

@mfh7

Description

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

  1. Run opencode serve --service.
  2. Immediately start opencode -c while the server-side provider instance is still booting (plugin setup: catalog fetch + probes).
  3. The server logs GET /api/model http.status=503 (span ≈ 5000 ms) exactly once.
  4. 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.
  5. /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).

Activity

  1. opencodejr commented on Oct 31, 2026

    @opencodejr
    Contributor

    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.

  2. opencodejr commented on Nov 3, 2026

    @opencodejr
    Contributor

    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.

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