gitbutlerapp/gitbutler · error

' ' already exists

Error message

'{path}' already exists

What it means

The worktree-add helper refuses to create a linked worktree at a filesystem path that already exists, because `git worktree add` would fail or, worse, write into an occupied directory. The check happens before invoking git.

Solutions

  1. Choose a fresh, non-existent path for the new worktree
  2. Remove the existing directory if it is stale or empty before calling add
  3. Run `git worktree prune` and manually delete leftover directories from removed worktrees
  4. Check `path.exists()` (or list registered worktrees) before calling to pick a unique name

Example fix

// before: blind add that can collide
add(&repo, &Path::new("../wt-feature"), branch, base)?;
// after: ensure the path is free first
let path = Path::new("../wt-feature");
if path.exists() { std::fs::remove_dir_all(path)?; } // or pick another name
add(&repo, path, branch, base)?;
Defensive patterns

Strategy: validation

Validate before calling

let path = Path::new("../wt-feature");
anyhow::ensure!(!path.exists(), "worktree path {} already exists", path.display());

Try / catch

match add(&repo, &path, branch, base) {
    Err(e) if e.to_string().contains("already exists") => pick_alternate_path_and_retry(),
    r => r,
}

Prevention

When it happens

Trigger: Calling worktrees::add(repo, path, branch, base) where path.exists() is true — the target directory is already present (occupied by a project, an empty folder, or a stale worktree directory left behind by a manual deletion).

Common situations: Re-running an idempotent setup script without pruning previous worktrees; stale directories left after `git worktree prune` (prune removes metadata but not stray files); a user- or IDE-created directory at the intended path; case-insensitive filesystems colliding with an existing name.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/4072de51584d4d2e. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-workspace/src/worktrees.rs:113

        args.push(OsStr::new("--force"));
    }
    args.extend([OsStr::new("--"), path.as_os_str()]);
    git_worktree(repo, "remove", &args)
}

/// Create a linked worktree at `path` on the new branch `branch` starting at `base`, the way
/// `git worktree add -b` does, which refuses an existing branch.
///
/// An existing `path` is refused up front, as git would only notice it after creating the branch.
/// Returns the stable name git gave the worktree, normally the last component of `path`.
pub fn add(
    repo: &gix::Repository,
    path: &Path,
    branch: &gix::refs::FullNameRef,
    base: gix::ObjectId,
) -> anyhow::Result<BString> {
    if path.exists() {
        bail!("'{}' already exists", path.display());
    }
    let short_name = gix::path::from_bstr(branch.shorten());
    let base = base.to_string();
    git_worktree(
        repo,
        "add",
        &[
            OsStr::new("-b"),
            short_name.as_os_str(),
            OsStr::new("--"),
            path.as_os_str(),
            OsStr::new(&base),
        ],
    )?;
    gix::open(path)?
        .worktree()
        .and_then(|worktree| worktree.id().map(ToOwned::to_owned))
        .context("git registered the new checkout as a linked worktree")

View on GitHub (pinned to 58e5313667)