GitoxideLabs/gitoxide · error

could not read reference to pin

Error message

could not read reference to pin: {err}

What it means

While building the set of references to pin in the ref-tree, iteration over `refs.all()` returned a per-reference error that was not the tolerated "missing ref" condition. Any other I/O or parse failure reading a reference is converted to this anyhow error wrapping the original `err`.

Solutions

  1. Fix the underlying ref error reported in `{err}` — check permissions and file contents under `.git/refs` and `packed-refs`.
  2. Stop concurrent git processes (gc, pack-refs, fetch) that may be rewriting refs, then retry.
  3. Run `git fsck` to detect and repair corrupted reference files.
  4. If a genuinely unreadable ref should be skipped, extend the match arm to log and `continue` instead of returning, mirroring the `is_missing_ref` arm.

Example fix

// before
Err(err) => return Err(anyhow::anyhow!("could not read reference to pin: {err}")),
// after
Err(err) if crate::history::is_missing_ref(&*err) => continue,
Err(err) => {
    eprintln!("skipping unreadable reference: {err}");
    continue;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Probe ref readability before pinning:
let readable = std::fs::read_dir(repo_path.join("refs")).is_ok()
    && std::fs::read(repo_path.join("packed-refs")).is_ok();

Try / catch

match pin_selection(&repo, ...) {
    Err(e) if e.to_string().starts_with("could not read reference to pin") => {
        eprintln!("A ref file is unreadable/corrupt: {e}; run git fsck and check permissions");
    }
    res => res?,
}

Prevention

When it happens

Trigger: Calling the ref-tree pinning path (ref_tree.rs:829) when a reference file cannot be read — e.g. a packed-refs entry is malformed, the loose ref file exists but is unreadable, or a filesystem/permission error occurs mid-iteration — and the error does not match `crate::history::is_missing_ref`.

Common situations: Concurrent `git gc`/`git pack-refs` rewriting refs while the TUI is open; permission problems on `.git/refs` or `packed-refs`; a corrupted or hand-edited ref file containing a non-OID value.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/8d37d8bcd564dd32. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/ref_tree.rs:829

    pin_references_reporting(repository, id, kinds).map(|(pins, _changes)| pins)
}

pub(crate) fn pin_references_reporting(
    repository: &gix::Repository,
    id: ObjectId,
    kinds: &[DecorationKind],
) -> anyhow::Result<(Vec<crate::history::Pin>, Vec<crate::edit::undo::RefChange>)> {
    let mut names = Vec::new();
    for reference in repository
        .references()
        .context("could not open references while pinning the ref-tree selection")?
        .all()
        .context("could not iterate references while pinning the ref-tree selection")?
    {
        let mut reference = match reference {
            Ok(reference) => reference,
            Err(err) if crate::history::is_missing_ref(&*err) => continue,
            Err(err) => return Err(anyhow::anyhow!("could not read reference to pin: {err}")),
        };
        let name = reference.name().to_owned();
        let Some(kind) = pinnable_kind(crate::history::decoration_kind(name.as_bstr())) else {
            continue;
        };
        if !kinds.contains(&kind) {
            continue;
        }
        let Ok(target) = reference.peel_to_id() else {
            continue;
        };
        if target.as_ref() != id {
            continue;
        }
        names.push(name);
    }
    names.sort();
    names.dedup();

View on GitHub (pinned to e73179060b)