[BUG] Desktop (Linux): claude://resume handled twice imports a CLI worktree session without worktreePath, then "branch is checked out somewhere else" on every message

Status Open
Reported on v2.1.289
Maintainer reply None cached
Activity 0 comments · opened Oct 4, 2026

Environment

  • Claude desktop app 2.19675.0 (Linux)
  • Claude Code CLI 2.1.289

Summary

Opening a CLI session with claude://resume?session=<id> breaks the imported session when its cwd is a CLI worktree under <repo>/.claude/worktrees/<name>. Every later attempt to use the session fails with:

Git is installed but isn't working: this session's branch is checked out somewhere else in this repository (run git worktree list in the repository folder to see where). Switch that checkout to a different branch, then try again.

The "somewhere else" is the session's own worktree, which still exists with the session's branch checked out.

What happens

Each claude://resume link is handled twice, concurrently. One xdg-open call produces two Resume deep link: importing CLI session <id> lines in the same second, and a Starting app { line from the second instance appears right after:

[info] Resume deep link: importing CLI session <session-id>
[info] Resume deep link: importing CLI session <session-id>
[info] Starting app {
[info] Registered external worktree "<name>" at <repo>/.claude/worktrees/<name> for session local_<session-id>
[info] Detected CLI worktree "<name>" at <repo>/.claude/worktrees/<name> (base repo: <repo>)
[info] Imported CLI session <session-id> as Desktop session local_<session-id>
[info] Worktree at <repo>/.claude/worktrees/<name> is already tracked (another session), skipping registration
[info] Imported CLI session <session-id> as Desktop session local_<session-id>

The first import registers the worktree in git-worktrees.json with leasedBy: local_<session-id>. The second import then finds a lease holder for the path. That holder is the same session, but the import treats it as "another session". It clears worktreePath/worktreeName and writes the session record without them, overwriting the first, correct record.

Result: the session JSON has cwd = the worktree and branch = its branch, but no worktreePath. On every warm-up Desktop runs Creating worktree for session … from <repo>, then refuses because the branch is checked out in that existing folder:

[error] the session's branch is checked out in a folder that exists; not recreating its worktree { refused: 'refs/heads/worktree-<name> is checked out at a folder that exists, or at a path not safe to look at' }
[error] [CCD] Failed to warm session local_<session-id>: Git is installed but isn't working: this session's branch is checked out somewhere else in this repository …

git-worktrees.json still holds the entry leased by that same session (adopted: true).

Expected

  • A deep link is handled once (or the import is idempotent under concurrency).
  • In importCliSession, a lease held by the importing session itself (leaseHolderForPath(path) === sessionId) is accepted, not treated as another session.

Reproduce

  1. In a repo, run claude -w some-name (or any CLI session whose cwd is <repo>/.claude/worktrees/<name>) and exit.
  2. With Desktop running, run xdg-open "claude://resume?session=<that session id>".
  3. Open the session in Desktop: the error above appears on every message.

Seen since 2.16120.0 and still present in 2.19675.0. Deep links were already logged twice in September, but CLI worktree detection on import is new, and that is what makes the duplicate harmful. Related: #95893.

View original on GitHub ↗