gitbutlerapp/gitbutler · error
Cannot derive a worktree directory from
Error message
Cannot derive a worktree directory from '{}' What it means
This error is thrown when creating a new worktree at a base commit but the reference name for the worktree cannot be turned into a non-empty directory slug. The library derives the worktree directory name from the ref's short name via slug(); if the resulting slug is empty, there is no usable directory name and it bails. Typically this happens when no explicit ref is provided and unique_canned_refname() produced a name whose shortened form slugs to empty.
Solutions
- Pass an explicit new_ref with a normal branch name (letters/digits/hyphens) when calling worktree_new_at_base_with_perm
- Inspect the ref name being generated (unique_canned_refname) and fix or sanitize it so its shortened form yields a non-empty slug
- Add a pre-call check that slug(ref_name.shorten()) is non-empty
Example fix
// before
worktree_new_at_base_with_perm(..., None, ...)?;
// after
worktree_new_at_base_with_perm(..., Some(gix::refs::PartialName::from("my-feature")), ...)?; Defensive patterns
Strategy: validation
Validate before calling
let slug = slug(ref_name.shorten());
if slug.is_empty() {
return Err(anyhow::anyhow!("ref '{}' yields empty worktree slug", ref_name.shorten()));
} Prevention
- Always pass an explicit, well-formed ref name when creating worktrees programmatically
- Sanitize branch names (strip special characters) before deriving directory names
- Unit-test the slug function against unusual ref names
When it happens
Trigger: Calling worktree_new_with_perm / worktree_new_at_base_with_perm without an explicit new_ref so a generated refname is used, and slug(ref_name.shorten()) returns "" — e.g. the shortened ref consists only of characters stripped by slug().
Common situations: Programmatic callers passing unusual or empty ref names; a refname generator yielding names with only slash/special characters; locales or edge-case branch names that normalize away entirely.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- worktree-changes are always set if there are hunks
- a committed transaction always materializes a workspace
- anchor is always present in the order at this point
- another pre-commit hook is already using the repository…
- argument ' ' must be a non-negative integer that fits in…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/3aaa805e8450e7e0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-api/src/worktrees.rs:343
worktree_new_at_base_with_perm(ctx, new_ref, base, perm)
}
/// Create a worktree at a given base.
pub fn worktree_new_at_base_with_perm(
ctx: &but_ctx::Context,
new_ref: Option<gix::refs::FullName>,
base: gix::ObjectId,
perm: &mut RepoExclusive,
) -> Result<NewWorktree> {
ensure_worktree_manipulation_enabled(ctx)?;
let (repo, ws, db) = ctx.workspace_and_db_with_perm(perm.read_permission())?;
let ref_name = match new_ref {
Some(ref_name) => ref_name,
None => unique_canned_refname(&repo)?,
};
let slug = slug(ref_name.shorten());
if slug.is_empty() {
bail!(
"Cannot derive a worktree directory from '{}'",
ref_name.shorten()
);
}
let path = repo.common_dir().join("gb-wts").join(&slug);
let name = but_workspace::worktrees::add(&repo, &path, ref_name.as_ref(), base)?;
let path = gix::path::realpath(&path)?;
drop((repo, ws, db));
ctx.invalidate_workspace_cache()?;
Ok(NewWorktree {
name,
path,
ref_name,
base,
})
}
/// Turn `name` into a single lowercase ASCII path component, keeping letters and digits andView on GitHub (pinned to 58e5313667)