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 switch races session creation and gets a Session not found toast #57354
The TUI asks the server to switch a session's model before the server has stored that session, so the server answers 404 SessionNotFoundError and the TUI shows a red toast:
Failed to prepare session
Failed to switch model: Session not found: ses_ea7beb81effeGcyHs8y0qQt2Fj
The session does exist — it is the tab the user is working in. It was created a moment earlier and the server had not committed it yet, so the switch is rejected even though the id is correct.
The client already sends its prompts behind the session creation (packages/client/src/solid/data.ts gates session.prompt on the in-flight create). The model switch taken from the composer selection is not gated that way, so it can leave first.
From the server log, the switch leaves 152 ms before the session is created (time.created = 07:40:36.919Z):
From the home route, send a prompt so a new session is created and opened in a tab.
Before the create request has been answered, press Enter again in the session tab with an empty composer. That commits the composer selection, which switches the session's model.
The toast above appears.
A session the server does not know yet answers the switch with 404:
POST /api/session/ses_ea7beb81effeGcyHs8y0qQt2Fj/model
HTTP/1.1 404 Not Found
{"_tag":"SessionNotFoundError","sessionID":"ses_ea7beb81effeGcyHs8y0qQt2Fj","message":"Session not found: ses_ea7beb81effeGcyHs8y0qQt2Fj"}
Screenshot
The toast is a red box in the top right of the TUI, title Failed to prepare session and the message above.
Thanks for the detailed report! I reproduced this on 2.1.0, and it still happens on the latest dev (d30e990).
Steps:
From the home route, send a prompt. This creates a new session and opens it in a tab.
About 150 ms later, while the create request is still in flight, press Enter with the composer empty in that tab.
The red toast Failed to prepare session / Failed to switch model: Session not found: ses_… appears.
On Linux the create is normally too fast to hit this. To widen the window, the script below adds random network delay between the TUI and the server, so the model switch can reach the server before the create. The race only shows some of the time, so the script may need a few runs. The recording and screenshots below show the toast.
As you pointed out, prompts already wait for the in-flight create (sendAdmission in packages/client/src/solid/data.ts). The composer's agent/model commit in packages/tui/src/component/prompt/index.tsx calls switchAgent/switchModel directly, without waiting.
recording.mp4
Reproduction script (drive.ts)
// Reproduces anomalyco/opencode#57354: an empty Enter in a freshly created// session tab sends POST /api/session/:id/model before the session create has// been committed, and the TUI shows "Failed to switch model: Session not found".import{Effect}from"effect"import{Llm,OpenCodeDriver}from"opencode-drive"// The report takes as given that the server stores the new session a little// after the TUI fires the model switch (152 ms in the author's log on// Windows). Locally both are near-instant, so the TUI<->server link is routed// through opencode-drive's chaos proxy with per-chunk jitter: requests on// different connections can then reach the server in either order. The race// is probabilistic: the toast appeared in 1 of 1 runs on 2.1.0 and 1 of 8 on// dev, so re-run a few times if waitFor times out.exportdefaultOpenCodeDriver.use({
...(process.env.OC_DEV ? {opencode: {dev: process.env.OC_DEV}} : {}),network: true,tui: {recording: true,keypressOverlay: true},},({ ui, llm, network })=>Effect.gen(function*(){yield*llm.queue(Llm.text("Hello from the simulated model."))yield*ui.screenshot("01-home")yield*Effect.sleep(3000)// let the TUI finish loading over the proxyyield*network.set({jitterMs: 1500})// Send a prompt from home: this creates a new session and opens it.yield*ui.submit("Say hello")// Immediately press Enter with an empty composer in the new session,// which commits the composer's model selection (switchModel).yield*Effect.sleep(150)yield*ui.screenshot("02a-session-tab")yield*ui.enter()yield*Effect.sleep(1500)yield*ui.screenshot("02-after-empty-enter")yield*ui.waitFor("Session not found",{timeout: 8000})yield*ui.screenshot("03-toast")yield*Effect.sleep(1500)}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
Activity
opencode-agent commentedon Oct 20, 2026
Thanks for the detailed report! I reproduced this on 2.1.0, and it still happens on the latest
dev(d30e990).Steps:
Failed to prepare session/Failed to switch model: Session not found: ses_…appears.On Linux the create is normally too fast to hit this. To widen the window, the script below adds random network delay between the TUI and the server, so the model switch can reach the server before the create. The race only shows some of the time, so the script may need a few runs. The recording and screenshots below show the toast.
As you pointed out, prompts already wait for the in-flight create (
sendAdmissioninpackages/client/src/solid/data.ts). The composer's agent/model commit inpackages/tui/src/component/prompt/index.tsxcallsswitchAgent/switchModeldirectly, without waiting.recording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.Bearmancer commentedon Oct 20, 2026
This was generated by AI during triage.
Fix PR: #57361