Skip to content

tui: "Choose directory" on a false location-unavailable prompt waits for the running step and does not clear the prompt #56958

Closed as not planned

Description

@ZhenningLang

Description

The false "Session location unavailable" prompt (#55250) often shows up while the agent is still running. In that state, the recovery action does not get the user out of the prompt. You have to quit the TUI and run opencode -s <id> again.

What I saw (directory exists and is a valid git worktree the whole time):

  1. The TUI is attached to the shared local service. The agent is in the middle of a long step (high-reasoning model, several minutes).
  2. The prompt appears. It lines up with the hourly location services evicted sweep in location-activity.ts. At that moment the service evicted ~17 idle locations at once, including the TUI's own launch directory. That directory differs from the session's directory because I resumed with -s from another worktree.
  3. I press "Choose directory" and pick the same directory.
  4. session.move sees the session is active (sourceUnavailable returns false). It enqueues a move inbox item with delivery: "steer". That item is only applied at the runner's next step boundary.
  5. The prompt keeps replacing the composer until then. In the database, the move I chose at 12:54:43 was applied (location-switched, same directory as previous) at 13:01:07, 6.5 minutes later. At 13:08:15 another move to the same directory was queued from the prompt.

Why it does not clear on its own (from reading the source, not instrumented): LocationProvider only clears error inside sync(). sync() only runs on set() when the location changes, or on server.connected. A move to the same directory does not change the location, so nothing calls sync() again.

How often: my DB has 30 location-switched messages where location.directory === previous.location.directory, across 34 sessions, in 4 days. Each one is this recovery flow being used on a directory that was fine.

Suggestions:

  • Retry the failed sync (fix(tui): tolerate transient failures in the post-reconnect location sync #55258 covers the reconnect case). Also re-sync when session.moved arrives, even when the directory is unchanged.
  • When the chosen directory equals the session's current directory, re-sync and clear the error locally instead of enqueueing a move behind the running step.
  • Show error.cause in the prompt. Today any one failing request out of ~13 (vcs, agent, command, mcp, model, provider, skill, config …) is reported as "location unavailable".

Related: #55250 (trigger: transient sync failure), #43415 (user trapped while the agent keeps running).

Plugins

local plugin (custom hooks); not involved in the failing path as far as I can tell

OpenCode version

0.0.0-dev-21164 (dev channel, shared service via opencode serve --service)

Steps to reproduce

  1. Run several TUIs against the shared service, each on a different git worktree. Resume one session with opencode -s <id> from a different directory.
  2. Start a long agent step in that session.
  3. Wait for the hourly location eviction sweep, or anything that makes one of the location sync requests fail.
  4. "Session location unavailable" shows up. Choose directory → pick the same directory.
  5. The prompt stays until the current step ends, and often after that too. Quitting and resuming fixes it.

Operating System

macOS 27.0.1

Terminal

tmux

Activity

  1. opencode-agent commented on Oct 19, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed write-up and the source analysis. I tried to reproduce this on v2.0.32 (the latest release; your dev-channel build can't be installed here) with a simulated model held in a long step. I couldn't get the false "Session location unavailable" prompt to appear in the first place, so I couldn't check what "Choose directory" → same directory does afterwards. Here is what I tried to make the location sync fail:

    • Repeatedly cutting the TUI's connections to the server, with added latency, so the reconnect-time sync would fail
    • Refusing new connections right after the event stream reconnected
    • Briefly hiding the session directory and forcing a reconnect

    In each case the TUI reconnected and synced without showing the prompt. The test proxy can only drop or refuse connections, not return an HTTP error from one sync endpoint, and the trigger you describe (the hourly eviction sweep on a shared service with many locations) wasn't practical to simulate.

    What you found in the code matches what I read: LocationProvider only clears error inside sync(), nothing re-syncs on session.moved, and an active session's move is queued until the next step boundary. Any of these would help someone reproduce it:

    • The failing request and its error when the prompt appears, if you can capture it from the service logs (e.g. which /api/... call failed, and its status)
    • Whether it still happens on a current 2.x release

    Related: #55250 (false prompt after a transient sync failure), #55258 and #55940 (open PRs aimed at that trigger), #43415 (user stuck in the prompt while the agent keeps running).

  2. opencode-agent commented on Oct 22, 2026

    @opencode-agent
    Contributor

    We haven't heard back, so I'm closing this as not planned for now. On v2.0.32 I couldn't get the false "Session location unavailable" prompt to appear during a running step, so I couldn't check what "Choose directory" → same directory does after it.

    If you see it again, please comment here with:

    • the request that failed when the prompt appeared, and its error or status, from the service logs
    • whether it still happens on a current 2.x release

    We can reopen it then. In the meantime, the trigger is tracked in #55250 (with open PRs #55258 and #55940), and being stuck while the agent keeps running is tracked in #43415. Thanks for the detailed analysis.

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