gitbutlerapp/gitbutler · error
Expected ' ' to be a remote tracking branch, but was
Error message
Expected '{ref_name}' to be a remote tracking branch, but was {category:?} What it means
Thrown by RefInfo::for_ui when the reference it was given categorizes as something other than a remote tracking branch (e.g. a local branch, tag, or note ref). The function exists solely to build UI metadata for remote-tracking refs, so any other category is rejected. The categorization comes from gix's ref_name.category_and_short_name().
Solutions
- Ensure the ref is under refs/remotes/ before calling for_ui; use the tracking ref, not the local branch.
- Check ref_name.category_and_short_name() yourself first and pick the right UI path per category.
- If the branch has no upstream, create/push a tracking branch or handle the no-remote case in the caller.
Example fix
// before
RefInfo::for_ui(repo, ref_name, remotes)?; // may be a local branch
// after
let (category, _) = ref_name.category_and_short_name()?;
if category == Category::RemoteBranch {
RefInfo::for_ui(repo, ref_name, remotes)?;
} else {
local_ref_info(ref_name)?;
} Defensive patterns
Strategy: type-guard
Validate before calling
fn is_remote_branch(ref_name: &gix::refs::FullNameRef) -> bool {
matches!(ref_name.category_and_short_name(), Ok((Category::RemoteBranch, _)))
} Type guard
// narrowing helper
fn as_remote_branch(r: &gix::refs::FullNameRef) -> Option<&str> {
let (cat, short) = r.category_and_short_name().ok()?;
(cat == Category::RemoteBranch).then(|| short.as_bstr().to_str().ok())?.map(str::to_owned)
} Try / catch
match RefInfo::for_ui(...) {
Err(e) if e.to_string().contains("remote tracking branch") => local_ref_info(ref_name)?,
other => other?,
} Prevention
- Verify the ref category before choosing the UI metadata builder
- Pass refs/remotes/* refs to remote-specific helpers, local branches elsewhere
- Handle branches without upstreams explicitly instead of forcing remote-ref helpers
When it happens
Trigger: Calling for_ui with a fully-qualified ref like refs/heads/main (local branch) or refs/tags/v1 instead of refs/remotes/origin/main; or after a ref rewrite changed the ref's category.
Common situations: Passing the workspace's local ref name instead of its upstream counterpart into remote-ref UI helpers; ambiguous or renamed refs after fetch/prune; callers assuming every workspace ref has a remote.
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
- Can only delete local branches under refs/heads, got
- Invalid branch_ref_bytes in assignment request for
- target ref ' ' must be a remote tracking branch
- Aborting due to empty branch name
- Branch name ' ' collides with existing branch
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/a0dbd78366bf2ca0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-workspace/src/ui/ref_info.rs:67
pub display_name: String,
/// The symbolic name of the remote, like `origin`, or `origin/other`.
pub remote_name: String,
}
#[cfg(feature = "export-schema")]
but_schemars::register_sdk_type!(RemoteTrackingReference);
impl RemoteTrackingReference {
/// Create a new instance from `ref_name` and `remote_names`, essentially splitting the remote
/// name off the short name.
pub fn for_ui(
ref_name: gix::refs::FullName,
remote_names: &gix::remote::Names,
) -> anyhow::Result<Self> {
let (category, _short_name) = ref_name.category_and_short_name().with_context(|| {
format!("Failed to categorize presumed remote reference '{ref_name}'")
})?;
if category != Category::RemoteBranch {
bail!("Expected '{ref_name}' to be a remote tracking branch, but was {category:?}");
}
let (longest_remote, short_name) =
extract_remote_name_and_short_name(ref_name.as_ref(), remote_names)
.ok_or(anyhow::anyhow!(
"Failed to find remote branch's corresponding remote"
))
.with_context(|| {
format!(
"Remote reference '{ref_name}' couldn't be matched with any known remote"
)
})?;
Ok(RemoteTrackingReference {
display_name: short_name.to_str_lossy().into_owned(),
remote_name: longest_remote,
full_name_bytes: ref_name.into_inner(),
})
}View on GitHub (pinned to 58e5313667)