GitoxideLabs/gitoxide · warning
HEAD is valid name
Error message
HEAD is valid name
What it means
This is a Rust `expect()` panic in `gix_ref::store::file::Store::find_one_with_verified_input` (reached via `try_find`, `try_find_loose`, `try_find_packed`, `find_existing_inner`). When a partial name lookup like `origin` fails, the store retries by appending `HEAD` (i.e. `origin/HEAD`); joining `"HEAD"` onto the precomposed partial name uses `Path::join`-like `join("HEAD")` and the `expect("HEAD is valid name")` asserts that this join can never produce an invalid `FullName`. It only panics if the precomposed partial name itself was not a valid partial ref name (violating the function's 'verified input' contract).
Solutions
- Validate the partial name with `gix_ref::validate` (or use `PartialNameRef::try_from` / `gix_ref::partial_name` constructors) before passing it to `try_find`.
- Normalize user-supplied ref lookups through the public `gix` repository API (`repo.find_reference`), which validates names first.
- Trim/limit user input so the name plus `/HEAD` stays within ref-name constraints.
- If the panic occurs with ordinary branch names, report it upstream with the exact name; it is an internal invariant violation.
Example fix
// before store.try_find(&mut buf, PartialName::from(user_input))? // after let partial = PartialNameRef::try_from(user_input.as_bstr())?; // validates first store.try_find(&mut buf, partial)?
Defensive patterns
Strategy: validation
Validate before calling
use gix_ref::partial_name::PartialNameRef; let partial = PartialNameRef::try_from(user_input.as_bstr())?; // reject invalid names early
Type guard
fn safe_partial(input: &[u8]) -> Option<gix_ref::partial_name::PartialNameRef<'_>> {
gix_ref::partial_name::PartialNameRef::try_from(bstr::BStr::new(input)).ok()
} Prevention
- Validate partial names before store lookups
- Prefer the high-level gix::Repository::find_reference API
- Limit user-supplied ref name length and character set
When it happens
Trigger: Calling `try_find`/`find` on the file ref store with a partial name that passes loose-ref verification but, when suffixed with `/` + `HEAD`, exceeds ref-name rules (e.g. a component containing invalid bytes, or a name already at maximum length).
Common situations: Hand-constructed partial names passed to low-level `gix_ref` store APIs; ref names built from user input without going through validation; extremely long branch names near the name-length limit.
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
- ' ' is not a valid configuration key
- Cannot use iter_v1() on index of type
- Cannot use iter_v2() on index of type
- BUG: tries to obtain object id from symbolic target
- BUG: expected peeled reference target but found symbolic one
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/d90a5417e3590961.
Report an issue: GitHub.
Appendix: source
Thrown at gix-ref/src/store/file/find.rs:132
precomposed_partial_name,
packed,
&mut buf,
consider_pseudo_ref,
) {
Ok(Some(r)) => return Ok(Some(decompose_if(r, precomposed_partial_name.is_some()))),
Ok(None) => {
if consider_pseudo_ref && is_pseudo_ref(partial_name.as_bstr()) {
break 'try_directories;
}
continue;
}
Err(err) => return Err(err),
}
}
}
if partial_name.as_bstr() != "HEAD" {
if let Some(mut precomposed) = precomposed_partial_name_storage {
precomposed = precomposed.join("HEAD".into()).expect("HEAD is valid name");
precomposed_partial_name_storage = Some(precomposed);
}
self.find_inner(
"remotes",
partial_name
.to_owned()
.join("HEAD".into())
.expect("HEAD is valid name")
.as_ref(),
precomposed_partial_name_storage
.as_ref()
.map(std::convert::AsRef::as_ref),
None,
&mut buf,
true, /* consider-pseudo-ref */
)
.map(|res| res.map(|r| decompose_if(r, precomposed_partial_name_storage.is_some())))
} else {View on GitHub (pinned to e73179060b)