GitoxideLabs/gitoxide · error
could not read local branch
Error message
could not read local branch: {err} What it means
While building the set of local branches for history decoration, tix iterates the repository's branch references. If reading an individual reference fails for a reason other than a transient missing-ref condition (e.g. packed-refs vs loose ref I/O errors, permission problems), the error is wrapped as `could not read local branch: {err}` and returned instead of skipping the branch.
Solutions
- Fix filesystem permissions on `.git/refs` and `.git/packed-refs`
- Run `git fsck` to find and repair corrupt or dangling ref files
- Remove stale lock files under `.git/refs` if a previous operation crashed
- Identify the failing branch name from the wrapped error and delete/repair that specific ref
Defensive patterns
Strategy: try-catch
Validate before calling
// check refs are readable before collecting branches
fn refs_readable(git_dir: &std::path::Path) -> bool {
let heads = git_dir.join("refs/heads");
match std::fs::read_dir(&heads) {
Ok(entries) => entries.all(|e| e.map(|e| e.metadata().map(|m| !m.permissions().readonly()).unwrap_or(true)).unwrap_or(false)),
Err(_) => git_dir.join("packed-refs").exists(),
}
} Type guard
fn is_missing_ref_error(err: &dyn std::error::Error) -> bool {
err.to_string().to_lowercase().contains("not found")
} Try / catch
match collect_local_branches(&repo) {
Ok(branches) => branches,
Err(e) if e.to_string().starts_with("could not read local branch") => {
eprintln!("branch refs unreadable: {e}; repairing refs");
repair_refs(&repo)?;
collect_local_branches(&repo)?
}
Err(e) => return Err(e),
} Prevention
- Keep `.git/refs` free of stale `.lock` files
- Run `git fsck` periodically on active repositories
- Avoid running multiple writers on the same repo from flaky mounts
- Fix permission problems on `.git` after user/OS changes
When it happens
Trigger: Calling the branch-collection API (the function preparing local branches for peeling, e.g. during history load) when `repo.references()` yields an `Err` on a branch ref that `is_missing_ref` does not classify as ignorable — such as I/O or permission errors reading loose or packed refs.
Common situations: Filesystem permission issues on `.git/refs`, partially written or corrupt loose ref files, packed-refs locks, or network/filesystem mount problems on remotes-backed worktrees.
Understand the failure class
Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.
Related errors
- could not inspect a reference before rebasing
- could not read reference
- One or more errors occurred - checkout is incomplete
- could not inspect a reference before editing
- {err}
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/bcc2fbdb1c5a2851.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/history.rs:960
.enumerate()
.filter(|(_, flags)| flags & (VISIBLE | HIDDEN) == VISIBLE | HIDDEN)
.map(|(index, _)| graph.id(CommitIndex(index as u32)))
.collect())
}
fn local_refs_by_target(repo: &gix::Repository) -> Result<HashMap<ObjectId, Vec<BString>>> {
let mut out = HashMap::<ObjectId, Vec<BString>>::new();
let platform = repo.references().context("could not open references")?;
let refs = platform
.local_branches()
.context("could not iterate local branches")?
.peeled()
.context("could not prepare local branches for peeling")?;
for reference in refs {
let reference = match reference {
Ok(reference) => reference,
Err(err) if is_missing_ref(&*err) => continue,
Err(err) => return Err(anyhow::anyhow!("could not read local branch: {err}")),
};
out.entry(reference.id().detach())
.or_default()
.push(reference.name().as_bstr().to_owned());
}
Ok(out)
}
fn resolve_tracking(repo: &gix::Repository, names: &[BString]) -> Result<Vec<SelectionRef>> {
let mut out = Vec::with_capacity(names.len());
for full_name in names {
let Some(reference) = repo
.try_find_reference(full_name.as_bstr())
.with_context(|| format!("could not read local branch {full_name}"))?
else {
continue;
};
let upstream = referenceView on GitHub (pinned to e73179060b)