GitoxideLabs/gitoxide · info
name conversion infallible
Error message
name conversion infallible
What it means
`Reference::log_exists` calls `Store::reflog_exists`, which returns a Result because the reference name must be converted/validated into a filesystem path. The `expect("name conversion infallible")` asserts this conversion can never fail for a `Reference` that has already been parsed and validated, so a panic here means the internal invariant (an already-validated ref name is always convertible) was broken.
Solutions
- Check how the `Reference` value was obtained; only pass references produced/validated by gix-ref into `log_exists`
- If the reference was constructed manually, validate the name first (e.g. via `gix_ref::Reference::try_from_path` or name validation APIs)
- If it reproduces with store-provided references, report a gix-ref bug including the ref name and repository layout
- As a workaround, call `store.reflog_exists(name)` yourself and handle the returned Result instead of the panicking convenience method
Example fix
// before (manual, unvalidated name)
let r = gix_ref::Reference { name: name.try_into()? /* unvalidated */, .. };
let exists = r.log_exists(&store);
// after
let exists = store.reflog_exists(r.name.as_ref()).expect("why does this fail?"); Defensive patterns
Strategy: validation
Validate before calling
fn name_is_valid(ref_name: &gix_ref::PartialNameRef<'_>) -> bool { gix_ref::name::partial::check(ref_name).is_ok() } // validate before constructing a Reference manually Type guard
fn is_store_reference(r: &gix_ref::Reference) -> bool { !r.name.as_bstr().is_empty() && r.name.as_bstr().starts_with(b"refs/") } Try / catch
// expect() panics cannot be caught in Rust; isolate with catch_unwind if truly needed let exists = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| r.log_exists(&store))).unwrap_or(false);
Prevention
- Only use Reference values obtained from the store (find/iteration), never hand-built ones
- Prefer `store.reflog_exists(name)` and handle the Result over the panicking convenience wrapper
- Keep gix-ref updated; these expects encode library invariants
- If a panic occurs, capture the ref name and repo layout for a bug report
When it happens
Trigger: Calling `Reference::log_exists(&store)` on a reference whose name fails path conversion inside `reflog_exists`. With a normal `Reference` obtained from the store this is unreachable; it only fires if the reference was constructed from a name that bypassed validation.
Common situations: Effectively never hit by library users; if seen it is almost always a gix-ref bug, or code that hand-built a `Reference` with a malformed/unvalidated name (e.g. containing invalid bytes or path components) rather than one obtained via `store.find`/iteration.
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
- always with parent directory
- infallible name conversion
- only value and unspecified are possible here
- parent-match assures this
- upper match already assured we only deal with blobs
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/9a284849ef40b1da.
Report an issue: GitHub.
Appendix: source
Thrown at gix-ref/src/store/file/loose/reference/logiter.rs:22
};
pub(crate) fn must_be_io_err(err: loose::reflog::Error) -> std::io::Error {
match err {
loose::reflog::Error::Io(err) => err,
loose::reflog::Error::RefnameValidation(_) => unreachable!("we are called from a valid ref"),
}
}
impl Reference {
/// Returns true if a reflog exists in the given `store`.
///
/// Please note that this method shouldn't be used to check if a log exists before trying to read it, but instead
/// is meant to be the fastest possible way to determine if a log exists or not.
/// If the caller needs to know if it's readable, try to read the log instead with a reverse or forward iterator.
pub fn log_exists(&self, store: &file::Store) -> bool {
store
.reflog_exists(self.name.as_ref())
.expect("name conversion infallible")
}
/// Return a reflog reverse iterator for this ref, reading chunks from the back into the fixed buffer `buf`, in the given `store`.
///
/// The iterator will traverse log entries from most recent to oldest, reading the underlying file in chunks from the back.
/// Return `Ok(None)` if no reflog exists.
pub fn log_iter_rev<'b>(
&self,
store: &file::Store,
buf: &'b mut [u8],
) -> std::io::Result<Option<log::iter::Reverse<'b, std::fs::File>>> {
store.reflog_iter_rev(self.name.as_ref(), buf).map_err(must_be_io_err)
}
/// Return a reflog forward iterator for this ref and write its file contents into `buf`, in the given `store`.
///
/// The iterator will traverse log entries from oldest to newest.
/// Return `Ok(None)` if no reflog exists.
pub fn log_iter<'a, 'b: 'a>(View on GitHub (pinned to e73179060b)