GitoxideLabs/gitoxide · error · anyhow::Error

repository at must have a worktree checkout

Error message

repository at {:?} must have a worktree checkout

What it means

Thrown by `validate_baseline` when computing an attribute/exclude baseline that requires reading ignore (`ignore=true`) rules from disk, but the repository has no working tree checkout. Ignore files live in the workdir, so with a bare repository the baseline cannot include ignore rules.

Solutions

  1. Run validation against a non-bare clone that has a worktree checkout
  2. Omit the ignore option and validate only attribute (`.gitattributes`) rules, which can come from the index/refs
  3. Create a worktree for the bare repo (`git worktree add`) and run against it

Example fix

// before (bare repo, ignore requested)
gix repo attributes validate-baseline --ignore
// after (non-bare clone)
gix repo attributes validate-baseline --ignore
Defensive patterns

Strategy: validation

Validate before calling

if ignore_requested && repo.workdir().is_none() {
    return Err("ignore baseline requires a worktree checkout; clone non-bare".into());
}

Type guard

fn can_read_ignore_rules(repo: &gix::Repository) -> bool {
    repo.workdir().is_some()
}

Prevention

When it happens

Trigger: Calling `gix repo attributes validate-baseline --ignore` (via `validate_baseline`) on a bare repository where `repo.workdir()` returns `None` while ignore handling was requested.

Common situations: Validating attributes on a server bare clone, or after `git clone --bare`, while still passing ignore-related flags that expect a checked-out worktree with `.gitignore` files.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/913ac58ed4b27683. Report an issue: GitHub.

Appendix: source

Thrown at gitoxide-core/src/repository/attributes/validate_baseline.rs:124

                    let mut lines = stdout.lines().map_while(Result::ok).peekable();
                    while let Some(baseline) = parse_attributes(&mut lines) {
                        if tx_base.send(baseline).is_err() {
                            child.kill().ok();
                            break;
                        }
                    }

                    Ok(())
                }
            });
            tx
        };
        let work_dir = ignore
            .then(|| {
                #[expect(clippy::unnecessary_debug_formatting)]
                repo.workdir()
                    .map(ToOwned::to_owned)
                    .ok_or_else(|| anyhow!("repository at {:?} must have a worktree checkout", repo.path()))
            })
            .transpose()?;
        let feed_excludes = ignore.then(|| {
            let (tx, rx) = std::sync::mpsc::sync_channel::<BString>(100);
            std::thread::spawn({
                let path = work_dir.expect("present if we are here");
                let tx_base = tx_base.clone();
                let mut progress = progress.add_child("excludes");
                move || -> anyhow::Result<()> {
                    let mut child =
                        std::process::Command::from(gix::command::prepare(gix::path::env::exe_invocation()))
                            .args(["check-ignore", "--stdin", "-nv", "--no-index"])
                            .stdin(std::process::Stdio::piped())
                            .stdout(std::process::Stdio::piped())
                            .stderr(std::process::Stdio::null())
                            .current_dir(path)
                            .spawn()?;

View on GitHub (pinned to e73179060b)