{"record":{"id":"2653e23cc9aeb076","repo":"gitbutlerapp/gitbutler","slug":"failed-to-determine-remote-and-branch-name-for-b","errorCode":null,"errorMessage":"failed to determine remote and branch name for `{branch}`","messagePattern":"failed to determine remote and branch name for `(.+?)`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gitbutler-git/src/context.rs","lineNumber":325,"sourceCode":") -> std::result::Result<S::Ok, S::Error>\nwhere\n    S: serde::Serializer,\n{\n    branch_to_remote\n        .iter()\n        .map(|(branch_name, refname, remote_branch_name)| {\n            (branch_name, refname.to_string(), remote_branch_name)\n        })\n        .collect::<Vec<_>>()\n        .serialize(serializer)\n}\n\nfn remote_tracking_branch_parts(\n    repo: &gix::Repository,\n    branch: &gix::refs::FullNameRef,\n) -> Result<(String, String)> {\n    let (remote, short_name) = extract_remote_name_and_short_name(branch, &repo.remote_names())\n        .ok_or_else(|| anyhow!(\"failed to determine remote and branch name for `{branch}`\"))?;\n    let short_name = std::str::from_utf8(short_name.as_ref())\n        .context(format!(\"branch name for `{branch}` is not valid UTF-8\"))?\n        .to_owned();\n    Ok((remote, short_name))\n}\n\nfn now_ms() -> u128 {\n    UNIX_EPOCH\n        .elapsed()\n        .expect(\"system time is set before the Unix epoch\")\n        .as_millis()\n}\n\nasync fn handle_git_prompt_push(\n    prompt: String,\n    askpass: Option<Option<StackId>>,\n) -> Option<String> {\n    if let Some(branch_id) = askpass {","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/gitbutler-git/src/context.rs#L307-L343","documentation":"remote_tracking_branch_parts (crates/gitbutler-git/src/context.rs) delegates to but_core::extract_remote_name_and_short_name and errors when it returns None. That helper returns None when the ref is not a refs/remotes/* ref at all, when no configured remote name prefixes the shorthand, and when the fallback for stray remote-tracking refs fails — the fallback assumes the remote is the first slash-separated component and refuses (None) if the remaining short name itself contains a slash (e.g. refs/remotes/unknown/feature/x).","triggerScenarios":"Passing a local branch ref (refs/heads/...) or a tag to a function that only accepts remote-tracking refs; a stray RTB like refs/remotes/gone/feature/sub after the remote 'gone' was removed, whose leftover short name 'feature/sub' contains a slash; remote_names from a different repo than the ref.","commonSituations":"Remote removed/renamed without pruning, leaving nested remote-tracking refs; refs created by tools that write under refs/remotes/ with multi-slash names; code iterating ALL references and feeding non-RTB refs into remote_tracking_branch_parts.","solutions":["Prune or delete the stale ref: `git remote prune <remote>` or `git update-ref -d refs/remotes/<stale-remote>/<branch>`","Re-register the remote whose name prefixes the ref so the primary match succeeds: `git remote add <name> <url>`","Filter inputs: only pass refs categorized as gix::refs::Category::RemoteBranch to remote-tracking helpers","Check the ref spelling at the call site (refs/remotes/ vs refs/heads/)"],"exampleFix":"// before\nlet (remote, short_name) = remote_tracking_branch_parts(&repo, branch)?;\n\n// after: pre-filter refs that the helper cannot resolve\nlet names = repo.remote_names();\nmatch but_core::extract_remote_name_and_short_name(branch, &names) {\n    Some((remote, short)) => (remote, short.to_string_lossy().into_owned()),\n    None => {\n        tracing::warn!(\"skipping unresolvable ref {}\", branch.as_bstr());\n        continue;\n    }\n}","handlingStrategy":"validation","validationCode":"let names = repo.remote_names();\n// but_core::extract_remote_name_and_short_name returns Option — use it as the pre-check\nif but_core::extract_remote_name_and_short_name(branch, &names).is_none() {\n    // not a resolvable remote-tracking ref: skip or report instead of calling in and failing\n    tracing::warn!(\"unresolvable remote-tracking ref {}\", branch.as_bstr());\n    continue;\n}\nlet (remote, short) = remote_tracking_branch_parts(&repo, branch)?;","typeGuard":"fn is_resolvable_rtb(r: &gix::refs::FullNameRef, remotes: &gix::remote::Names) -> bool {\n    but_core::extract_remote_name_and_short_name(r, remotes).is_some()\n}","tryCatchPattern":"match remote_tracking_branch_parts(&repo, branch) {\n    Ok(parts) => parts,\n    Err(err) if err.to_string().contains(\"failed to determine remote and branch name\") => {\n        tracing::warn!(\"stray remote-tracking ref {} — consider pruning\", branch.as_bstr());\n        continue;\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Prune remote-tracking refs whenever remotes are removed or renamed","Only feed refs categorized as gix::refs::Category::RemoteBranch into remote-tracking helpers","Prefer but_core::extract_remote_name_and_short_name directly when you need Option semantics instead of errors"],"tags":["git","refs","remote-tracking","gix","gitbutler"],"backgroundTag":"remote-name-resolution-failed","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}