GitoxideLabs/gitoxide · info

a parent is always there unless empty

Error message

a parent is always there unless empty

What it means

`IterInfo::from_prefix` computes the iteration root for a prefix search; when the computed root has a prefix, it takes `iter_root.parent()`. The `expect("a parent is always there unless empty")` asserts that any non-empty path has a parent component. A panic means the derived iteration root was empty or a bare root with no parent where one was required.

Solutions

  1. Check where the repository's git-dir/common-dir actually reside; avoid pathological roots like `/`
  2. Verify environment overrides (`GIT_DIR`, `GIT_COMMON_DIR`) aren't pointing at a bare root
  3. Simplify the layout (normal clone location) and retry the prefix iteration
  4. If it reproduces on a standard repo, report a gix-ref bug with the exact prefix and layout
Defensive patterns

Strategy: validation

Validate before calling

// Check the derived root is a usable directory before prefix iteration
fn root_ok(git_dir: &std::path::Path) -> bool { git_dir.parent().is_some() && git_dir.is_dir() }

Try / catch

// Panic path; validate layout up front instead of catching
if !root_ok(git_dir) { return Err("unusable git-dir location"); }

Prevention

When it happens

Trigger: Calling prefix-scoped reference iteration (e.g. `store.iter(prefix)` / listing refs under a prefix) where the root path derivation yields a path with no parent — internal path-derivation bug or a degenerate/unusual git-dir path.

Common situations: Unusual git-dir locations (e.g. git-dir at filesystem root `/`), heavily customized or symlinked layouts, or a gix-ref bug in root normalization. Ordinary `repo.references()?.iter_prefix(...)` calls never hit it.

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/3cffce6cccf929cc. Report an issue: GitHub.

Appendix: source

Thrown at gix-ref/src/store/file/overlay_iter.rs:329

            } => SortedLoosePaths::at(base, base.into(), None, Some("HEAD".into()), precompose_unicode),
        }
        .peekable()
    }

    fn from_prefix(base: &'a Path, prefix: &'a RelativePath, precompose_unicode: bool) -> std::io::Result<Self> {
        let prefix_path = gix_path::from_bstr(prefix.as_ref().as_bstr());
        let iter_root = base.join(&prefix_path);
        if prefix.as_ref().ends_with(b"/") {
            Ok(IterInfo::BaseAndIterRoot {
                base,
                iter_root,
                prefix: prefix_path.into_owned(),
                precompose_unicode,
            })
        } else {
            let iter_root = iter_root
                .parent()
                .expect("a parent is always there unless empty")
                .to_owned();
            Ok(IterInfo::ComputedIterationRoot {
                base,
                prefix: prefix.as_ref().as_bstr().into(),
                iter_root,
                precompose_unicode,
            })
        }
    }
}

impl file::Store {
    /// Return an iterator over all references, loose or `packed`, sorted by their name.
    ///
    /// Errors are returned similarly to what would happen when loose and packed refs were iterated by themselves.
    pub fn iter_packed<'s, 'p>(
        &'s self,
        packed: Option<&'p packed::Buffer>,

View on GitHub (pinned to e73179060b)