zed-industries/zed · error · anyhow::Error

git.worktree_directory must be a relative path, got: {worktr

Error message

git.worktree_directory must be a relative path, got: {worktree_directory_setting:?}

What it means

Zed validates the git.worktree_directory setting before creating a managed git worktree (crates/project/src/git_store.rs:10492). The value must be relative because it is joined onto the repository anchor path; absolute POSIX paths, Windows drive-letter paths, and values starting with a backslash are rejected up front (an explicit leading-slash check compensates for Windows Path::is_absolute() requiring a drive letter).

Source

Thrown at crates/project/src/git_store.rs:10492

/// - The setting must not be an absolute path.
/// - The resolved path must be either a subdirectory of the working
///   directory or a subdirectory of its parent (i.e., a sibling).
///
/// Returns `Ok(resolved_path)` or an error with a user-facing message.
pub fn worktrees_directory_for_repo(
    repository_anchor_path: &Path,
    worktree_directory_setting: &str,
    path_style: PathStyle,
) -> Result<PathBuf> {
    // Check the original setting before trimming, since a path like "///"
    // is absolute but becomes "" after stripping trailing separators.
    // Also check for leading `/` or `\` explicitly, because on Windows
    // `Path::is_absolute()` requires a drive letter — so `/tmp/worktrees`
    // would slip through even though it's clearly not a relative path.
    if path_style.is_absolute(worktree_directory_setting)
        || worktree_directory_setting.starts_with('\\')
    {
        anyhow::bail!(
            "git.worktree_directory must be a relative path, got: {worktree_directory_setting:?}"
        );
    }

    if worktree_directory_setting.is_empty() {
        anyhow::bail!("git.worktree_directory must not be empty");
    }

    let trimmed = worktree_directory_setting.trim_end_matches(['/', '\\']);
    if trimmed == ".." {
        anyhow::bail!("git.worktree_directory must not be \"..\" (use \"../some-name\" instead)");
    }

    let joined = path_style.join_path(repository_anchor_path, trimmed)?;
    let resolved = if path_style.is_posix() {
        joined
    } else {
        path::normalize_path(&joined)

View on GitHub (pinned to f4178619ac)

Solutions

  1. Use a relative path such as ".zed-worktrees" (resolved inside the repository)
  2. To place worktrees next to the repository, use "../my-repo-worktrees"
  3. Remove the setting entirely to fall back to the default location

Example fix

// settings.json - before
{ "git": { "worktree_directory": "/tmp/worktrees" } }

// settings.json - after
{ "git": { "worktree_directory": "../my-repo-worktrees" } }
Defensive patterns

Strategy: validation

Validate before calling

fn assert_relative_worktree_directory(setting: &str) -> Result<(), String> {
    if setting.starts_with('/')
        || setting.starts_with('\\')
        || Path::new(setting).is_absolute()
    {
        return Err(format!("git.worktree_directory must be a relative path, got: {setting:?}"));
    }
    Ok(())
}

Prevention

When it happens

Trigger: Setting "git": { "worktree_directory": "/tmp/worktrees" } (or "C:\\worktrees", "\\worktrees") in settings.json, then creating a worktree. A value like "///" also lands here because it is absolute before trailing separators are trimmed.

Common situations: Users copying an absolute path they previously passed to git worktree add into settings; Windows drive-letter paths; leading-backslash values.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/84ac090f1fbc681d. Report an issue: GitHub.