Skip to content

Bug: catalog refresh is scoped to the first workspace, leaving other workspaces stale #57580

Closed as duplicate

Description

@VanNamdigital

Summary

The shared models.dev catalog refresh emits models-dev.refreshed with an ambient Location. Other already-open workspaces filter out that event and retain stale provider/model definitions. Newly opened workspaces or global Settings can show the updated catalog at the same time.

This is present in upstream OpenCode v2.0.32, commit 843a6c514e606b436a7fe713422ace0a93ad3d61, before downstream branding changes. Confirmed on Windows x64 with the V2 background server and multiple workspace Locations.

Expected behavior

A successful refresh of the shared catalog updates every loaded workspace. Settings and workspace model pickers should agree about which catalog models are available, subject to intentional configuration and visibility overrides.

Actual behavior

Only the workspace matching the refresh fiber's ambient Location receives the refresh event. Other workspaces keep their old definitions. Waiting for another five-minute poll may not recover them because an unchanged catalog digest skips publication entirely.

Observed example: Settings had deepseek-v4.1-flash-free and marked muse-spark-1.3-contributor-free deprecated, while an existing workspace still exposed Muse Free and did not expose DeepSeek Free. There were no OpenCode model overrides in that workspace. Reloading Location services synchronized it immediately. Closing and reopening only the GUI can reuse the same background service and stale Location graph.

Deterministic reproduction

  1. Start a server with a private profile and OPENCODE_MODELS_URL pointing to a local HTTP server serving /api.json.
  2. Serve an initial catalog with an OpenCode free model, for example catalog-smoke-old-free, with text/tool capabilities and zero input/output cost.
  3. Load workspace A and workspace B through /api/model?location[directory]=.... Confirm both expose the initial model.
  4. Change the local HTTP catalog to replace the initial model with catalog-smoke-new-free.
  5. Allow the real five-minute refresh to run, or advance TestClock by five minutes in an in-process test using the real LocationServiceMap and plugin activation.
  6. Query the two existing workspaces again, without calling /api/location/reload.

Before the fix, an in-process reproduction produced:

{
  "refreshEventLocation": "workspace-A",
  "workspaceA": "new catalog",
  "workspaceB": "old catalog"
}

After the fix:

{
  "refreshEventLocation": null,
  "workspaceA": "new catalog",
  "workspaceB": "new catalog"
}

The ModelsDev service identity was checked across the real Location graphs: it is shared. This is an event-routing bug, not a separate service instance per workspace.

Root cause

The automatic refresh fiber in packages/core/src/models-dev.ts can inherit the Location context of the workspace that first acquires the shared service.

Bus.publish in packages/core/src/bus.ts defaults to the ambient Location.Service unless global: true is explicitly supplied. Bus.subscribe filters located events for each workspace.

The current refresh call does not specify global delivery:

yield* bus.publish(ModelsDev.Event.Refreshed, {})

The per-Location ModelsDevPlugin subscribes to this event to update its retained snapshot and reload integrations/providers. A sibling Location never receives an event addressed to the first Location, so its retained snapshot stays old.

Relevant upstream sources:

Proposed fix

Broadcast shared catalog refreshes globally:

- yield* bus.publish(ModelsDev.Event.Refreshed, {})
+ yield* bus.publish(ModelsDev.Event.Refreshed, {}, { global: true })

This preserves catalog caching, digest checks, refresh intervals, and per-session model selection. The event is ephemeral and contains no catalog payload or credentials.

Validation

  • Added refresh publishes globally when called from a Location to packages/core/test/models.test.ts. It fails before the fix because the event carries a workspace Location; it passes after the fix.
  • Real two-Location graph and automatic refresh test: before the fix only A updates; after the fix both A and B update.
  • A compiled downstream backend containing this patch was tested with a private profile and local HTTP catalog using the actual timer: both existing workspaces updated after 302.159 seconds, with zero inference requests and zero Location reload requests.
  • Catalog/plugin suites: 30 tests passed, repeated ten times for 300 passes and zero failures.
  • Repository lint/typecheck: 35/35 tasks passed.

The source fix and regression are attached separately as OpenCode-catalog-global-refresh.patch. No issue has been submitted automatically.

Scope

This report concerns stale catalog synchronization. It does not attribute free-tier HTTP 403 errors or model deprecations to this bug. A separate GUI smoke attempt failed inside a restricted test environment and is not evidence of an upstream GUI regression.

Activity

  1. opencode-agent commented on Oct 21, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report and root-cause analysis. I think this duplicates #57148, which fixes exactly this problem and has already been merged.

    Possible duplicates and related items, ordered from most to least likely:

    The fix first ships in v2.1.1; v2.0.32 and v2.1.0 still have the old call. After upgrading, make sure the background service restarts so it runs the new version.

    The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different, for example if you still see stale workspaces on v2.1.1.

  2. opencode-agent commented on Oct 22, 2026

    @opencode-agent
    Contributor

    Closing this as a duplicate of #57148, since there's been no reply in the past day. That PR fixes this bug: models-dev.refreshed is now published server-wide with { global: true }, so every open workspace gets catalog refreshes, not just the first one. The fix shipped in v2.1.1.

    Thanks again for the detailed analysis and reproduction steps. If you still see stale catalogs in other workspaces on v2.1.1 or later, after restarting the background service, please comment here or open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions