GitoxideLabs/gitoxide · error
could not read reference
Error message
could not read reference: {err} What it means
When collecting reference decorations for history, tix iterates all references in the repository. Most errors reading an individual ref are skipped only if they indicate the ref went missing mid-iteration; any other failure is wrapped as `could not read reference: {err}` and aborts the decoration pass.
Solutions
- Run `git fsck` and inspect `.git/refs` / `.git/packed-refs` for corruption
- Fix permissions on the `.git` directory and ref files
- Stop concurrent git/tix processes that may be rewriting refs, then retry
- Identify the specific failing ref from the wrapped error and repair or delete it
Defensive patterns
Strategy: try-catch
Validate before calling
// sanity-check all refs are readable before decoration pass
let output = std::process::Command::new("git")
.args(["for-each-ref", "--format=%(refname)"])
.output()
.expect("run git");
assert!(output.status.success(), "refs unreadable: {}", String::from_utf8_lossy(&output.stderr)); Type guard
fn is_benign_ref_error(err: &dyn std::error::Error) -> bool {
err.to_string().to_lowercase().contains("not found")
} Try / catch
match collect_ref_decorations(&repo, include_tags) {
Ok(decorations) => decorations,
Err(e) if e.to_string().starts_with("could not read reference") => {
eprintln!("a ref is unreadable: {e}");
repair_refs(&repo)?;
collect_ref_decorations(&repo, include_tags)?
}
Err(e) => return Err(e),
} Prevention
- Avoid concurrent ref-mutating processes during history rendering
- Repair packed-refs corruption with `git pack-refs --all` after backup
- Keep repository on a local filesystem, not a flaky network mount
- Audit `.git/refs` permissions when errors mention access
When it happens
Trigger: Calling the all-references iteration API (history decoration collection, around history.rs:1277) when the refs iterator returns an `Err` that is not a missing-ref condition — e.g. an unreadable loose ref, corrupt packed-refs entry, or permission error on any ref including tags and remote branches.
Common situations: Concurrent ref updates corrupting loose refs during iteration, restricted filesystem permissions, damaged packed-refs, or a repository on a flaky network mount.
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 local branch
- 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/e352d14994bf8ec2.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/history.rs:1277
revisions: &[OsString],
hidden: &[OsString],
include_worktrees: bool,
) -> Result<RefSnapshot> {
snapshot_ignoring_pin(repo, revisions, hidden, include_worktrees, None)
}
pub(crate) fn ref_tree_revisions(repo: &gix::Repository, include_tags: bool) -> Result<Vec<OsString>> {
let mut out = Vec::new();
for reference in repo
.references()
.context("could not open references")?
.all()
.context("could not iterate references")?
{
let mut reference = match reference {
Ok(reference) => reference,
Err(err) if is_missing_ref(&*err) => continue,
Err(err) => return Err(anyhow::anyhow!("could not read reference: {err}")),
};
let name = reference.name().as_bstr().to_owned();
let kind = decoration_kind(&name);
if matches!(kind, DecorationKind::Special | DecorationKind::Pin)
|| matches!(kind, DecorationKind::Tag) && !include_tags
|| name.starts_with(STASH_PREFIX)
|| name.starts_with(REVIEW_STASH_PREFIX)
{
continue;
}
let Ok(id) = reference.peel_to_id() else { continue };
if repo.find_header(id)?.kind() != gix::object::Kind::Commit {
continue;
}
out.push(gix::path::from_bstr(&name).into_owned().into_os_string());
}
if repo.head().is_ok_and(|head| head.referent_name().is_none()) {
out.push("HEAD".into());View on GitHub (pinned to e73179060b)