GitoxideLabs/gitoxide · error

Bug in lookup_symbol_has_path - must return lookup symbols

Error message

Bug in lookup_symbol_has_path - must return lookup symbols

What it means

An `unreachable!()` panic in `gix_protocol::handshake::refs::shared::parse_v1` when parsing a v1 ref advertisement. The code expects that whenever a symbolic-ref lookup matched (`lookup_symbol_has_path`), the matched internal ref is `SymbolicForLookup`; any other variant reaching that arm triggers the panic, flagging a bug in the match predicate.

Solutions

  1. Force protocol v2 (`GIT_PROTOCOL=version=2` equivalent in gix transport config) or use a transport/server combination that negotiates v2 and retry
  2. Upgrade gix / gix-protocol to the newest release; the panic marks a matcher bug to report upstream with the remote URL
  3. Work around by mirroring the remote with real `git clone` first and fetching from the local mirror
Defensive patterns

Strategy: try-catch

Try / catch

std::panic::catch_unwind(|| parse_v1_refs(advertisement))
    .map_err(|_| "protocol v1 ref parse failed; retry with protocol v2")?

Prevention

When it happens

Trigger: Performing a protocol v1 handshake (e.g. clone/fetch over a transport that negotiates v1) where the ref-name matching logic returns a hit whose internal ref variant is not `SymbolicForLookup` — possible with remotes advertising refs like `HEAD` plus similarly-named refs that confuse the matcher, indicating a gix bug.

Common situations: Cloning from older or non-standard Git servers (git-daemon, custom implementations, older GitLab/Gitea versions) that use protocol v1 and advertise symbolic refs inconsistently; mostly encountered as an upstream bug report.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at gix-protocol/src/handshake/refs/shared.rs:188

                    let id = gix_hash::ObjectId::from_hex(path)?;
                    out_shallow.push(ShallowUpdate::Shallow(id));
                    return Ok(());
                }
                Err(err) => return Err(err.into()),
            };
            match out_refs
                .iter()
                .take(num_initial_out_refs)
                .position(|r| r.lookup_symbol_has_path(path.into()))
            {
                Some(position) => match out_refs.swap_remove(position) {
                    InternalRef::SymbolicForLookup { path: _, target } => out_refs.push(InternalRef::Symbolic {
                        path: path.into(),
                        tag: None, // TODO: figure out how annotated tags work here.
                        object,
                        target,
                    }),
                    _ => unreachable!("Bug in lookup_symbol_has_path - must return lookup symbols"),
                },
                None => out_refs.push(InternalRef::Direct {
                    object,
                    path: path.into(),
                }),
            }
        }
    }
    Ok(())
}

pub(in crate::handshake::refs) fn parse_v2(line: &BStr) -> Result<Ref, Error> {
    let trimmed = line.trim_end();
    let mut tokens = trimmed.splitn(4, |b| *b == b' ');
    match (tokens.next(), tokens.next()) {
        (Some(hex_hash), Some(path)) => {
            let id = if hex_hash == b"unborn" {
                None

View on GitHub (pinned to e73179060b)