gitbutlerapp/gitbutler · error

Cannot currently work in repositories without a worktree

Error message

Cannot currently work in repositories without a worktree

What it means

Context::workdir_or_fail returns the repository's working directory, but bare repositories have none. The library cannot run worktree-dependent operations (file lookups, workspace commands) without a checkout, so it raises this anyhow error with code NOT_AUTHENTICATED-style plain message. It exists precisely to fail fast with a clear message instead of returning None.

Solutions

  1. Use a non-bare working clone of the repository
  2. If you must work with a bare repo, clone it to a working directory first and point but there
  3. Guard calls with a check for a worktree (repo.workdir().is_some()) and skip worktree-dependent operations otherwise

Example fix

// before
let dir = ctx.workdir_or_fail()?;
find_files(&ctx)?;
// after
let dir = match ctx.repo.get()?.workdir() {
    Some(_) => ctx.workdir_or_fail()?,
    None => anyhow::bail!("this command needs a checked-out worktree"),
};
Defensive patterns

Strategy: fallback

Validate before calling

if ctx.repo.get()?.workdir().is_none() {
    bail!("operation requires a checked-out worktree");
}

Type guard

fn has_worktree(ctx: &Context) -> bool { ctx.repo.get().ok().and_then(|r| r.workdir()).is_some() }

Try / catch

match ctx.workdir_or_fail() {
    Ok(dir) => use(dir),
    Err(e) if e.to_string().contains("without a worktree") => clone_working_copy()?,
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling workdir_or_fail (via set_active, handle_command_confirm, find_files, etc.) on a Context whose repository is bare (repo.workdir() returns None) — e.g. pointing but at a bare repo path or a repo opened via gitdir.

Common situations: Running `but` commands inside a bare repository or a --bare clone; automation that opens the .git directory directly; server-side repo paths without a checkout.

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 gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/0f2b5fc6b7594131. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-ctx/src/lib.rs:1002

    /// Fallible as it may need to open a repository.
    pub fn workdir_or_gitdir(&self) -> anyhow::Result<PathBuf> {
        let repo = self.repo.get()?;
        Ok(repo.workdir().unwrap_or(repo.git_dir()).to_owned())
    }

    /// Return the worktree directory associated with the context Git [repository](Self::repo).
    pub fn workdir(&self) -> anyhow::Result<Option<PathBuf>> {
        self.repo.get().map(|repo| repo.workdir().map(Into::into))
    }

    /// Return the worktree directory associated with the context Git [repository](Self::repo),
    /// or fail.
    ///
    /// # Try to gracefully degrade if there is no worktree!
    pub fn workdir_or_fail(&self) -> anyhow::Result<PathBuf> {
        let repo = self.repo.get()?;
        repo.workdir()
            .ok_or_else(|| anyhow!("Cannot currently work in repositories without a worktree"))
            .map(Into::into)
    }
}

/// *Repository* helpers, for when you need something more specific than [Self::repo].
impl Context {
    /// Open an isolated repository, one that didn't read options beyond `.git/config` and
    /// knows no environment variables.
    ///
    /// Use it for fastest-possible access, when incomplete configuration is acceptable.
    /// Note that [Self::repo].get() should be preferred.
    pub fn open_isolated_repo(&self) -> anyhow::Result<gix::Repository> {
        Ok(gix::open_opts(
            &self.gitdir,
            gix::open::Options::isolated(),
        )?)
    }

View on GitHub (pinned to 58e5313667)