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
- Use a relative path such as ".zed-worktrees" (resolved inside the repository)
- To place worktrees next to the repository, use "../my-repo-worktrees"
- 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
- Keep git.worktree_directory relative; use "../name" for sibling locations
- Validate user-supplied path settings in CI or editor linting before shipping configs
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
- git.worktree_directory must not be ".." (use "../some-name"
- git.worktree_directory must not be empty
- git.worktree_directory resolved to {resolved:?}, which is ou
- untracked files are present and will NOT be included in the
- A worktree already exists at {}
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/84ac090f1fbc681d.
Report an issue: GitHub.