GitoxideLabs/gitoxide · error
never without parent
Error message
never without parent
What it means
Panic raised by `.expect("never without parent")` on `reflog_path.parent()` while cleaning up empty reflog directories after a ref deletion. The invariant is that a reflog path always has a parent directory component; a `None` would mean the path was somehow just a root/file name, which cannot happen for valid reflog paths produced by the store.
Solutions
- Report the panic to the gitoxide project with the ref name and full stack trace.
- Check the deleted ref's name for pathological components that could break path construction.
- Update to a gix-ref version where reflog path handling is correct.
Defensive patterns
Strategy: validation
Validate before calling
// sanity-check the reflog path before deleting refs with reflogs let path = store.reflog_path(name); assert!(path.parent().is_some(), "reflog path must have a parent");
Prevention
- Use standard ref names so derived reflog paths are always nested under the reflog root.
- Report any panic here with the ref name as a gitoxide bug.
- Avoid exotic ref name components in tooling.
When it happens
Trigger: Committing a ref transaction with deletions whose reflog cleanup path computation yields a parentless path — per the invariant, only from an internal bug in reflog path construction, not normal usage.
Common situations: Practically never; possibly exposed by exotic ref names or a bug in reflog path derivation after a gix-ref upgrade.
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
- name conversion infallible
- infallible name conversion
- visit_non_tree() called us
- BUG: ResolvedSignatures don't exist here when nothing is set
- initial hunks are never ancestors
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/6094c9d2d5313155.
Report an issue: GitHub.
Appendix: source
Thrown at gix-ref/src/store/file/transaction/commit.rs:135
for change in &mut updates {
let (reflog_root, relative_name) = self.store.reflog_base_and_relative_path(change.update.name.as_ref());
match &change.update.change {
Change::Update { .. } => {}
Change::Delete { .. } => {
// Reflog deletion happens first in case it fails a ref without log is less terrible than
// a log without a reference.
let reflog_path = reflog_root.join(relative_name);
if let Err(err) = std::fs::remove_file(&reflog_path) {
if err.kind() != std::io::ErrorKind::NotFound {
return Err(Error::DeleteReflog {
source: err,
full_name: change.name(),
});
}
} else {
gix_tempfile::remove_dir::empty_upward_until_boundary(
reflog_path.parent().expect("never without parent"),
&reflog_root,
)
.ok();
}
}
}
}
if let Some(t) = self.packed_transaction {
t.commit().map_err(Error::PackedTransactionCommit)?;
// Always refresh ourselves right away to avoid races. We ignore errors as there may be many reasons this fails, and it's not
// critical to be done here. In other words, the pack may be refreshed at a later time and then it might work.
self.store.force_refresh_packed_buffer().ok();
}
for change in &mut updates {
let take_lock_and_delete = match &change.update.change {
Change::Update {View on GitHub (pinned to e73179060b)