worktree start crashes with EEXIST when a worktree-symlinks entry is a tracked file #1297

Open
opened 2026-10-23 22:22:18 +00:00 by jared · 2 comments
Owner

Problem

worktree start <name> crashes when .cc-os/config lists a path under worktree-symlinks that git already checks out in the new worktree. git worktree add creates the tracked file, then Worktree::Checkout#link_extra_paths calls FileUtils.ln_s on the same path and raises Errno::EEXIST. The worktree is left half-linked and the command exits 1 with a Ruby backtrace instead of a printed reason.

Observed

worktree start ticket-30
/home/jared/.rbenv/versions/4.0.2/lib/ruby/4.0.0/fileutils.rb:716:in 'File.symlink': File exists @ syserr_fail2_in - /home/jared/projects/finance/.claude/worktrees/ticket-30/.sdlc/project.yaml (Errno::EEXIST)
	from /home/jared/dev/cc-os/plugins/os/lib/worktree/checkout.rb:63:in 'block in Worktree::Checkout#link_extra_paths'

The finance repo tracks .sdlc/project.yaml (its .gitignore has !.sdlc/project.yaml) and its config had worktree-symlinks=.venv,.sdlc/project.yaml.

Reproduce

# in a repo whose .cc-os/config lists a git-tracked path in worktree-symlinks
worktree start ticket-x

Approach

Skip a symlink target that already exists in the new worktree, or print one line naming the entry and continue. A config check that warns when a worktree-symlinks entry is git-tracked would also prevent it.

Required work: none beyond the acceptance criteria.

Acceptance criteria

  1. Given a worktree-symlinks entry that git tracks, when worktree start runs, then it completes with the standard output lines and the tracked file is left as checked out.

Discoverer: /home/jared/projects/finance, session f6b97de2-a65d-4ecf-9dd4-848bc0302154, 2026-10-23. Hit while opening the ticket-30 worktree for /os-sdlc:implement; worked around by removing the tracked entry from the finance config.

## Problem `worktree start <name>` crashes when `.cc-os/config` lists a path under `worktree-symlinks` that git already checks out in the new worktree. `git worktree add` creates the tracked file, then `Worktree::Checkout#link_extra_paths` calls `FileUtils.ln_s` on the same path and raises `Errno::EEXIST`. The worktree is left half-linked and the command exits 1 with a Ruby backtrace instead of a printed reason. ## Observed ``` worktree start ticket-30 ``` ``` /home/jared/.rbenv/versions/4.0.2/lib/ruby/4.0.0/fileutils.rb:716:in 'File.symlink': File exists @ syserr_fail2_in - /home/jared/projects/finance/.claude/worktrees/ticket-30/.sdlc/project.yaml (Errno::EEXIST) from /home/jared/dev/cc-os/plugins/os/lib/worktree/checkout.rb:63:in 'block in Worktree::Checkout#link_extra_paths' ``` The finance repo tracks `.sdlc/project.yaml` (its .gitignore has `!.sdlc/project.yaml`) and its config had `worktree-symlinks=.venv,.sdlc/project.yaml`. ## Reproduce ``` # in a repo whose .cc-os/config lists a git-tracked path in worktree-symlinks worktree start ticket-x ``` ## Approach Skip a symlink target that already exists in the new worktree, or print one line naming the entry and continue. A config check that warns when a worktree-symlinks entry is git-tracked would also prevent it. Required work: none beyond the acceptance criteria. ## Acceptance criteria 1. Given a worktree-symlinks entry that git tracks, when `worktree start` runs, then it completes with the standard output lines and the tracked file is left as checked out. -------- **Discoverer:** /home/jared/projects/finance, session f6b97de2-a65d-4ecf-9dd4-848bc0302154, 2026-10-23. Hit while opening the ticket-30 worktree for /os-sdlc:implement; worked around by removing the tracked entry from the finance config.
Author
Owner

From #1589 port check: NOT FIXED. Links#link_extra checks only that the source exists (plugins/os-git/lib/os_git/worktree/links.rb:129-134), then Links#link calls FileUtils.ln_s on the target (links.rb:136-139). A git-tracked entry already exists in the new worktree, so ln_s raises Errno::EEXIST. Nothing rescues it in Start#create (plugins/os-git/lib/os_git/worktree/start.rb:202-211). The same applies to .cc-os at links.rb:33. Not closed.

From #1589 port check: NOT FIXED. Links#link_extra checks only that the source exists (plugins/os-git/lib/os_git/worktree/links.rb:129-134), then Links#link calls FileUtils.ln_s on the target (links.rb:136-139). A git-tracked entry already exists in the new worktree, so ln_s raises Errno::EEXIST. Nothing rescues it in Start#create (plugins/os-git/lib/os_git/worktree/start.rb:202-211). The same applies to .cc-os at links.rb:33. Not closed.
Author
Owner

Correction to the last comment: the verdict stands (not fixed), but the line reference was wrong. The code is plugins/os-git/lib/os_git/worktree/links.rb:75-78 (link).

Correction to the last comment: the verdict stands (not fixed), but the line reference was wrong. The code is plugins/os-git/lib/os_git/worktree/links.rb:75-78 (link).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#1297
No description provided.