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
fix(core): avoid holding models.dev refresh lock across network timeout #61118
When OpenCode boots, the background ModelsDev.refresh() loop in packages/core/src/models-dev.ts acquires lock.withPermit before awaiting fetchApi(), which has an Effect.timeout("10 seconds").
If models.dev is slow, firewalled, or unreachable, lock is held for up to 10 seconds. Meanwhile, foreground initialization calls ModelsDev.get(), which executes populate() and attempts to acquire lock.withPermit(). Consequently, foreground provider and agent initialization blocks for up to 10 seconds waiting on the lock, even when a valid cache or bundled snapshot already exists on disk. This causes the server to return HTTP 503 on /api/model, /api/agent, and /api/provider, stalling client startup.
fetchApi() only needs to run before taking the lock; lock.withPermit is only needed when decoding and writing to the cache.
Plugins
none
OpenCode version
2.2.5 (dev)
Steps to reproduce
Run OpenCode in an environment with high latency or a firewall blocking outbound requests to models.dev.
Start OpenCode (opencode).
Notice /api/model and /api/agent return HTTP 503 for up to 10 seconds while the log records: message="Failed to fetch models.dev" cause="Cause([Fail(TimeoutError: Operation timed out after '10s')])"
Screenshot
Not applicable (server lifecycle and background network lock timing issue).
Thanks for the detailed report! I tried this on 2.2.5 (Linux, opencode serve) and couldn't reproduce it.
To stand in for a firewalled or unreachable models.dev, I pointed OPENCODE_MODELS_URL at a local server that accepts connections and never responds. The server logged the same error you quoted, Failed to fetch models.dev ... TimeoutError: Operation timed out after '10s', so the background refresh did hold its lock for the full 10 seconds. Even so, /api/model, /api/agent and /api/provider returned 200 as soon as the server was up (about 0.5s for the first /api/model request), and every later request took a few milliseconds, including during the hang. I polled every 0.5s for 14s, once with an empty cache and once with a warm one, and saw no 503s.
This matches the code. ModelsDev.get() → populate() returns the cached catalog, or else the bundled snapshot, before it reaches lock.withPermit. It only waits on the lock when there is neither a cache nor a snapshot, and the snapshot is always bundled in normal builds. So a slow refresh() shouldn't block foreground initialization.
If you still see 503s, these would help:
The full server log from startup until the 503s stop (--print-logs --log-level debug), with timestamps.
The exact response body of one of the 503s. It usually names the service that isn't ready yet.
How you run it: the background service, opencode serve, or from source (you mentioned 2.2.5 (dev)). Also whether you set OPENCODE_MODELS_PATH, OPENCODE_DISABLE_MODELS_FETCH, or anything that disables the bundled snapshot.
Cross-referencing implementation and test evaluation in PR #61120, where the refresh flow and error handling have been exercised against simulated timeouts.
Closing this for now: we couldn't reproduce it on 2.2.5, and we haven't heard back with the details we asked for.
We pointed models.dev at a server that never responds. The background refresh did time out after 10s, but /api/model, /api/agent and /api/provider returned 200 right away and never 503. That matches the code: ModelsDev.get() returns the cache or the bundled snapshot before it waits on the refresh lock.
If you still see the 503s, please reply with a startup log (--print-logs --log-level debug), the body of one of the 503 responses, and how you run OpenCode (background service, opencode serve, or from source), and we'll take another look. Related startup-readiness reports: #36117, #60854. Thanks for the report!
Activity
opencodejr commentedon Nov 2, 2026
Thanks for the detailed report! I tried this on 2.2.5 (Linux,
opencode serve) and couldn't reproduce it.To stand in for a firewalled or unreachable models.dev, I pointed
OPENCODE_MODELS_URLat a local server that accepts connections and never responds. The server logged the same error you quoted,Failed to fetch models.dev ... TimeoutError: Operation timed out after '10s', so the background refresh did hold its lock for the full 10 seconds. Even so,/api/model,/api/agentand/api/providerreturned 200 as soon as the server was up (about 0.5s for the first/api/modelrequest), and every later request took a few milliseconds, including during the hang. I polled every 0.5s for 14s, once with an empty cache and once with a warm one, and saw no 503s.This matches the code.
ModelsDev.get()→populate()returns the cached catalog, or else the bundled snapshot, before it reacheslock.withPermit. It only waits on the lock when there is neither a cache nor a snapshot, and the snapshot is always bundled in normal builds. So a slowrefresh()shouldn't block foreground initialization.If you still see 503s, these would help:
--print-logs --log-level debug), with timestamps.opencode serve, or from source (you mentioned2.2.5 (dev)). Also whether you setOPENCODE_MODELS_PATH,OPENCODE_DISABLE_MODELS_FETCH, or anything that disables the bundled snapshot.Bearmancer commentedon Nov 2, 2026
Cross-referencing implementation and test evaluation in PR #61120, where the refresh flow and error handling have been exercised against simulated timeouts.
opencodejr commentedon Nov 5, 2026
Closing this for now: we couldn't reproduce it on 2.2.5, and we haven't heard back with the details we asked for.
We pointed models.dev at a server that never responds. The background refresh did time out after 10s, but
/api/model,/api/agentand/api/providerreturned 200 right away and never 503. That matches the code:ModelsDev.get()returns the cache or the bundled snapshot before it waits on the refresh lock.If you still see the 503s, please reply with a startup log (
--print-logs --log-level debug), the body of one of the 503 responses, and how you run OpenCode (background service,opencode serve, or from source), and we'll take another look. Related startup-readiness reports: #36117, #60854. Thanks for the report!