GitoxideLabs/gitoxide · error
we are called from a valid ref
Error message
we are called from a valid ref
What it means
An `unreachable!()` panic in `must_be_io_err`, an internal gix-ref helper that downcasts a loose reflog error to `std::io::Error`. The helper is only ever invoked from code paths operating on an already-validated ref name, so a `RefnameValidation` error variant is considered impossible; the panic fires if validation-style errors leak into those call sites.
Solutions
- Verify the reference name is valid: `git check-ref-format --branch <name>` or `repo.find_reference(name)` before touching its reflog
- Clean up malformed refs/reflog files under `.git/refs` and `.git/logs` (or recreate them with real git)
- Upgrade gix / gix-ref; if a public API lets an invalid name reach the reflog reader, report it upstream
Defensive patterns
Strategy: validation
Validate before calling
fn ref_name_is_valid(name: &str) -> bool {
// mirror git check-ref-format basics
!name.is_empty()
&& !name.starts_with('-')
&& !name.contains("..")
&& !name.ends_with(".lock")
&& !name.chars().any(|c| matches!(c, ' ' | '~' | '^' | ':' | '?' | '*' | '[' | '\\'))
&& name.split('/').all(|c| !c.is_empty() && c != "." && !c.ends_with(".lock"))
} Type guard
fn as_io_error(err: &gix_ref::store::file::loose::reflog::Error) -> Option<&std::io::Error> {
if let gix_ref::store::file::loose::reflog::Error::Io(e) = err { Some(e) } else { None }
} Try / catch
match std::panic::catch_unwind(|| read_reflog(ref)) {
Ok(Ok(data)) => data,
_ => Vec::new(), // treat unreadable/invalid reflog as absent
} Prevention
- Validate ref names with git check-ref-format rules before creating refs
- Avoid hand-creating refs or reflog files with unusual names/encodings
- Use gix's own find_reference to confirm a ref exists before reading its reflog
- Keep gix-ref current so validation and iteration agree on name validity
When it happens
Trigger: Reading or iterating the reflog of a reference (e.g. `Reference::reflog_iter` internals) where the underlying loose-reflog reader returns `loose::reflog::Error::RefnameValidation` — i.e. the ref name was actually invalid despite the caller assuming validity, typically due to a validation bypass elsewhere or corrupted refs storage.
Common situations: Repositories with hand-created or oddly-encoded ref files under `.git/refs/` or `.git/logs/` (case/encoding quirks, Windows-reserved names), or gix versions where validation and iteration disagree about name validity.
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
- BUG: Invalid state: we never discard only our file, always…
- ' ' is not a valid configuration key
- 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
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/4adce18c38f32a07.
Report an issue: GitHub.
Appendix: source
Thrown at gix-ref/src/store/file/loose/reference/logiter.rs:9
use crate::store_impl::{
file,
file::{log, loose, loose::Reference},
};
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.View on GitHub (pinned to e73179060b)