gitbutlerapp/gitbutler · error
Could not create branch '{}'
Error message
Could not create branch '{}' What it means
Second step of but-api's branch rename failed: creating the new ref with PreviousValue::MustNotExist was rejected — most often because a branch with the new name already exists (including case-insensitive collisions on macOS/Windows, or a race where another process created it first). The code then attempts to restore the old branch and remove the backup ref, so state should return to pre-rename; the surfaced error carries the wrapped creation failure.
Source
Thrown at crates/but-api/src/branch.rs:1381
if let Err(delete_err) = old_reference.delete() {
if let Some(backup) = backup_reference.take()
&& let Err(err) = backup.delete()
{
warn!(
?err,
"failed to remove branch-rename recovery ref after source deletion failed"
);
}
return Err(anyhow::Error::new(delete_err)
.context(format!("Could not delete branch '{}'", ref_name.as_bstr())));
}
if let Err(create_err) = repo.reference(
new_ref.as_ref(),
target_id,
PreviousValue::MustNotExist,
"rename branch",
) {
let create_err = anyhow::Error::new(create_err)
.context(format!("Could not create branch '{}'", new_ref.as_bstr()));
match repo.reference(
ref_name.as_ref(),
target_id,
PreviousValue::MustNotExist,
"restore branch after failed rename",
) {
Ok(_) => {
if let Some(backup) = backup_reference.take()
&& let Err(err) = backup.delete()
{
warn!(
?err,
"failed to remove branch-rename recovery ref after restoring source"
);
}
return Err(create_err);
}View on GitHub (pinned to 2497b8007a)
Solutions
- Pre-check that refs/heads/<new> does not exist (git rev-parse --verify or the API equivalent) before renaming.
- For case-only renames, go through a temporary intermediate name.
- If it fires anyway, verify with `git branch` that exactly one of old/new exists; if the auto-restore also failed, recreate the missing side manually.
- Retry once any competing operation finishes.
Example fix
// before
rename_branch(&ctx, &old_name, &new_name)?;
// after
if repo.find_reference(new_ref.as_ref()).is_ok() {
anyhow::bail!("a branch named '{new_ref}' already exists; choose another name");
}
rename_branch(&ctx, &old_name, &new_name)?; Defensive patterns
Strategy: validation
Validate before calling
if repo.find_reference(new_ref.as_ref()).is_ok() {
anyhow::bail!("a branch named '{new_ref}' already exists; choose another name");
} Try / catch
match rename_branch(&ctx, &old_name, &new_name) {
Err(e) if e.to_string().contains("Could not create branch") => {
// old branch was auto-restored; surface 'name taken' to the user
Err(anyhow::anyhow!("branch name '{new_name}' is already taken"))
}
r => r,
}? Prevention
- Filter existing branch names in rename dialogs.
- Use a two-step rename via a temporary name for case-only changes on macOS/Windows.
- Disable rename controls while other ref mutations are running.
When it happens
Trigger: Renaming onto an existing local branch name; case-only renames on case-insensitive filesystems where the 'new' name still collides with the old ref; concurrent creation of the same ref between the delete and create steps.
Common situations: Rename dialogs that do not filter taken names; users renaming 'feature' to 'Feature' on macOS/Windows; simultaneous git branch operations.
Related errors
- Could not delete branch '{}'
- No uncommitted changes found for the selected files
- Failed to determine target commit for hunk absorption due to
- Stack has no branches
- Failed to create blank commit in stack: {stack_id:?}
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/a6d68b89cc4057f4.
Report an issue: GitHub.