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
- Force protocol v2 (`GIT_PROTOCOL=version=2` equivalent in gix transport config) or use a transport/server combination that negotiates v2 and retry
- Upgrade gix / gix-protocol to the newest release; the panic marks a matcher bug to report upstream with the remote URL
- 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
- Prefer protocol v2 (`git clone` defaults to it) to avoid v1 parsing paths
- Test clones against your server fleet with gix before rolling out automation
- Keep gix-protocol current — v1 matcher bugs are patched upstream
- Mirror problem servers with real git and read from the local mirror instead
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
- this case should have been removed during processing
- BUG: tries to obtain object id from symbolic target
- BUG: expected peeled reference target but found symbolic one
- no item index implies having an object id
- this impl is needed to allow passing a known valid partial…
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" {
NoneView on GitHub (pinned to e73179060b)