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

  1. Validate the partial name with `gix_ref::validate` (or use `PartialNameRef::try_from` / `gix_ref::partial_name` constructors) before passing it to `try_find`.
  2. Normalize user-supplied ref lookups through the public `gix` repository API (`repo.find_reference`), which validates names first.
  3. Trim/limit user input so the name plus `/HEAD` stays within ref-name constraints.
  4. 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

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


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)