Repository navigation
Description
Summary
When the TUI reconnects after a brief network interruption, it can replace the composer
with the "Session location unavailable — Choose another directory to continue this session"
recovery prompt even though the session's directory is valid and unchanged. Selecting the
same directory resumes the session. No restart or upgrade is involved; any single failed
request in the post-reconnect location sync is enough to surface the false prompt.
Environment
- opencode version: 2.0.27 (client TUI and server)
- OS: Ubuntu 26.04.1 LTS, x86_64 (kernel 7.0.0-38-generic)
- Terminal: Unavailable: remote TUI over SSH; terminal app not discoverable from server
- Shell: bash
- Install/channel: latest
- Active plugins: superpowers@git+https://github.com/obra/superpowers.git
- Setup:
opencode servein Docker behind a reverse proxy + forward auth; client runs
opencode attach https://<host> --dir <workdir>on the same host. Four remote MCP
servers configured.
Reproduction
- Attach a TUI to a remote server and open a session in an existing directory.
- Briefly interrupt network/proxy connectivity so the event stream drops and reconnects.
- On reconnect the client re-runs the full location sync; if any one request fails
transiently, the composer is replaced by "Session location unavailable — Choose
another directory to continue this session." - Choose directory → select the current directory → session resumes normally.
Intermittent: depends on whether all requests in the post-reconnect burst succeed.
Expected Behavior
Reconnecting should not report a valid, unchanged directory as unavailable. Transient
sync failures should retry or stay non-blocking; the recovery prompt should only appear
when the location is actually missing or inaccessible.
Actual Behavior
Full-screen recovery prompt for a valid directory; the only offered action moves the
session to the same directory.
Additional Context
Root cause trace (v2.0.27; verified identical on dev on 2026-10-13):
- Every reconnect re-runs the location sync:
packages/tui/src/context/location.tsx:48—
onCleanup(client.event.on("server.connected", () => sync(ref()))). - While disconnected,
packages/client/src/solid/data.tsinvalidates all cached syncs
(createEffect→sync.invalidate()at the end ofcreateData), so the reconnect
re-runs the full fan-out. location.sync()(packages/client/src/solid/data.ts) awaitslocation.get, then
Promise.allover 12 location-scoped loads (vcs, agent, command, integration, mcp
servers, mcp resources, model, provider, reference, skill, shells, global forms).
Any single rejection rejects the whole sync.LocationProviderstores that rejection aserror; the session route matches
currentLocation.error?.location.directory === session()!.location.directoryand
rendersSessionLocationMissing(packages/tui/src/routes/session/index.tsx:1519-1531).- A transient data-refresh failure after reconnect is therefore presented as "location
unavailable", even though the directory exists (session.moveto the same directory
then works).
Related: #49352 (same false prompt, upgrade/version-skew trigger), #43415 (service
restart trigger, non-dismissible modal), #54943 (plugin model crash), #46322 (closed as
duplicate). Prior attempts to separate loading from sync failures: #45601, #46961 (closed).
Fix direction: treat location sync as degraded rather than unavailable on transient
failure (retry/backoff), and only escalate when location.get itself identifies a
missing/inaccessible directory.
Frequency: intermittent, several times over recent weeks; always recoverable by
choosing the same directory.
Activity
opencode-agent commentedon Oct 13, 2026
Thanks for the detailed trace. I could reproduce this on 2.0.27, and it still happens on the latest
dev(46e4695).Setup: a simulated model, plus a small HTTP reverse proxy between the TUI and
opencode serve.502toGET /api/agentfor about a second. Every other request goes through normally.Failing only the first such request wasn't always enough. A second location sync sometimes started right after and succeeded, so the failure has to land on the sync that ends up current. That fits the intermittent behaviour you described. The recording and screenshot below show the run from start to the prompt, and the script below reproduces it.
Related, ordered by likelihood:
timecrashes Model.snapshot and shows false "Session location unavailable" #54943: same prompt when a plugin model breaks model loadingrecording.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.Finn763 commentedon Oct 13, 2026
Taking this one. The fix belongs in the post-reconnect location sync: a single transient failure shouldn't surface the recovery prompt -- I'll add bounded retry/verification to that path and cover it with a test.
Finn763 commentedon Oct 13, 2026
PR is up: #55258 — the post-reconnect sync now retries a bounded number of times before surfacing the recovery prompt, so one transient 5xx no longer tears down the session view. The sync logic also moves into a
createLocationcreator (same pattern ascontext/session-retention) so this is pinned by tests; the transient-failure case is red on the base.robertn702 commentedon Oct 14, 2026
Observed the same false prompt on 2.0.28 on Linux, in an Orca-managed Git worktree connected to the local shared OpenCode service. It appeared while returning from a review subagent and interrupted the workflow.
The directory and
.gitwere readable, the TUI process cwd matched the worktree, and the stored session mappings pointed to the correct directory. The shared server did not restart at the time of the banner. The session later recovered in the original directory without choosing another location and completed its work.The investigation found the same broad location-sync error handling described above. We did not capture the rejected subrequest, so this observation does not establish a network interruption as the trigger. Another invocation installed 2.0.29 during this period, but both the existing TUI and shared server remained on 2.0.28. We cannot attribute the failure to that upgrade either.
yentsun commentedon Oct 16, 2026
Same false prompt on Windows, in a case where no interruption was involved.
2.0.30(opencode --version), CLI/TUI in Windows Terminal, Windows 10 x64 (10.0.19045.7807), local shared service athttp://127.0.0.1:45278.F:\Projects\personal\<repo>) is a local fixed NTFS volume (F:, DriveType 3). I verified it exists and is readable while the prompt was up, so the server's report of a missing location did not match the disk.~/.local/share/opencode/log/opencode.loghas noLocation not found/LocationNotFoundErrorentries for that period, but that log also records noserver.connectedevents, so its silence is inconclusive rather than evidence that the client failed the location sync on its own.What the occurrence did correlate with is CPU saturation: the machine was sitting at 100% CPU with a large number of Node.js processes competing for a few cores, and connectivity did not change. Hypothesis: a location-scoped request in the sync times out under CPU starvation, and because one rejection rejects the whole sync, it surfaces as the same false prompt as the reconnect case.
Selecting the current directory resumed the session, same as in @robertn702's report: valid directory, no captured failing subrequest. As of writing, #55258 is still open, so
2.0.30predates the bounded-retry change.If the intended fix is tolerating transient failures in the post-reconnect sync, it is worth knowing that the prompt can also surface with no reconnect at all, so a local resource stall (CPU saturation here) may be enough to trigger it.
WilliamAGH commentedon Oct 19, 2026
Same false prompt on 2.0.32 (macOS, local shared service) after a service restart, with the failing request pinned down.
After the restart, six attached TUIs (each in a different directory) re-ran their location sync at once.
GET /api/modelwaited on plugin activation for 5 s, then returned 503Location plugins did not finish activating. Every other request in the sync succeeded:Activation runs once per location: 0.9–3.2 s each with
opencode models --standalone, so six together pass 5 s on a busy host.For #55258: a 503 from the plugin gate means "not ready yet", so waiting for activation (or backing off) seems safer than a fixed 3 × 500 ms. Ideally the location prompt would show only on a real 404
LocationNotFoundError.