GitoxideLabs/gitoxide · info
always with parent directory
Error message
always with parent directory
What it means
When creating or appending to a reflog file, gix-ref derives the log path (`reflog_base.join(full_name)`) and asks for its parent directory to create leading directories. The `expect("always with parent directory")` asserts that a joined path always has a parent component. A panic means the ref name was empty or degenerate so `log_path.parent()` returned `None`.
Solutions
- Verify the reference name being written is a fully qualified, non-empty name like `refs/heads/main`
- Check `core.logAllRefUpdates` and any explicit reflog-creation flags to confirm which names trigger autocreate
- If it happens with a valid `refs/...` name, file a gix-ref bug with the ref name and config
- Work around by ensuring the reflog directory exists beforehand or by writing through a higher-level API that validates names
Example fix
// before let name = ""; // degenerate name reaching reflog creation repo.reference(name, target, true, log_message)?; // after let name = "refs/heads/main"; repo.reference(name, target, true, log_message)?;
Defensive patterns
Strategy: validation
Validate before calling
fn is_full_ref(name: &str) -> bool { name.starts_with("refs/") && !name.is_empty() } // check before triggering reflog writes Try / catch
// Panic, not an error type; use catch_unwind at a boundary if you must attempt recovery std::panic::catch_unwind(|| repo.reference(name, target, true, msg)).map(|r| r.ok())
Prevention
- Always use fully qualified ref names (`refs/heads/...`) when writing refs with reflogs
- Check `core.logAllRefUpdates` to know which refs get auto-created reflogs
- Don't pass empty or relative ref names to ref-writing APIs
- Report any reproduction as a gix-ref bug with the ref name
When it happens
Trigger: Calling an API that writes a reflog (e.g. ref creation/update with reflog enabled, `reflog_create_or_append`) with a reference name that produces a log path with no parent, which should be impossible for validated non-empty ref names.
Common situations: Practically unreachable for users; if observed it points to a gix-ref bug or to code passing an empty/degenerate full ref name into reflog creation with `force_create_reflog` or autocreate configured (e.g. `core.logAllRefUpdates` matching).
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
- BUG: Invalid state: we never discard only our file, always…
- we are called from a valid ref
- BUG: packed refs cannot contain symbolic refs, catch that…
- we have read non-zero bytes before
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/b49aef4a6df6583f.
Report an issue: GitHub.
Appendix: source
Thrown at gix-ref/src/store/file/loose/reflog.rs:120
name: &FullNameRef,
previous_oid: Option<ObjectId>,
new: &oid,
committer: Option<gix_actor::SignatureRef<'_>>,
message: &BStr,
mut force_create_reflog: bool,
) -> Result<(), Error> {
let (reflog_base, full_name) = self.reflog_base_and_relative_path(name);
match self.write_reflog {
WriteReflog::Normal | WriteReflog::Always => {
if self.write_reflog == WriteReflog::Always {
force_create_reflog = true;
}
let mut options = std::fs::OpenOptions::new();
options.append(true).read(false);
let log_path = reflog_base.join(&full_name);
if force_create_reflog || self.should_autocreate_reflog(&full_name) {
let parent_dir = log_path.parent().expect("always with parent directory");
gix_tempfile::create_dir::all(parent_dir, Default::default()).map_err(|err| {
Error::CreateLeadingDirectories {
source: err,
reflog_directory: parent_dir.to_owned(),
}
})?;
options.create(true);
}
let file_for_appending = match options.open(&log_path) {
Ok(f) => Some(f),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => None,
Err(err) => {
// TODO: when Kind::IsADirectory becomes stable, use that.
if log_path.is_dir() {
gix_tempfile::remove_dir::empty_depth_first(log_path.clone())
.and_then(|_| options.open(&log_path))
.map(Some)View on GitHub (pinned to e73179060b)