gitbutlerapp/gitbutler · error
Expected a local branch, but
Error message
Expected a local branch, but '{}' is a remote-tracking branch What it means
resolve_local_branch found a reference with the given name but of category RemoteBranch. `but branch update` only operates on local branches, so it rejects remote-tracking refs like refs/remotes/origin/main.
Solutions
- Use the local branch name without the remote prefix: `main` instead of `origin/main`.
- If only the remote branch exists, check out a local tracking branch first.
- Update a local branch that tracks the remote instead of the remote ref itself.
Example fix
// before but branch update origin/main --to abc123 // after but branch update main --to abc123
Defensive patterns
Strategy: validation
Validate before calling
if (name.startsWith('origin/') || name.startsWith('refs/remotes/')) {
name = name.replace(/^(refs\/remotes\/)?origin\//, '');
} Prevention
- Strip remote prefixes before passing branch names to but commands.
- Treat `but branch update` as local-branch-only; sync remotes with push/pull instead.
- When scripting from IDE data, sanitize refs to bare local names.
When it happens
Trigger: Passing a remote-tracking ref (e.g. `origin/main` or `refs/remotes/origin/main`) to `but branch update`, causing normalize_local_branch_ref's refs/ handling or the lookup to land on a RemoteBranch-category reference.
Common situations: Users habitually prefixing branches with `origin/` as in git workflows; scripts parameterized with remote refs; IDE-provided refs copied from the remote branch list.
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
- Branch ' ' not found
- Branch ' ' not found when checking for conflicts
- Expected a local branch, but
- Local branch ' ' not found
- No HEAD reference found for remote
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/af1ad8b934460549.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but/src/command/branch/update.rs:144
commit_id: commit_id.into(),
}
}
})
.collect(),
}
}
fn resolve_local_branch(ctx: &but_ctx::Context, branch: &str) -> anyhow::Result<FullName> {
let candidate = normalize_local_branch_ref(branch)?;
let repo = ctx.repo.get()?;
let Some(reference) = repo.try_find_reference(candidate.as_ref())? else {
bail!("Local branch '{}' not found", candidate.shorten());
};
let reference = reference.detach();
match reference.name.category() {
Some(Category::LocalBranch) => Ok(reference.name),
Some(Category::RemoteBranch) => {
bail!(
"Expected a local branch, but '{}' is a remote-tracking branch",
reference.name.shorten()
)
}
_ => bail!(
"Expected a local branch, but '{}' is not under refs/heads/",
reference.name.shorten()
),
}
}
fn normalize_local_branch_ref(branch: &str) -> anyhow::Result<FullName> {
let full = if branch.starts_with("refs/heads/") {
branch.to_owned()
} else if branch.starts_with("refs/") {
bail!("Only local branches under refs/heads/ are supported");
} else {
format!("refs/heads/{branch}")View on GitHub (pinned to 58e5313667)