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 worktree root and fails on bare repositories, where gix's workdir() is None (core.bare = true, or the path is a .git directory itself). The doc comment on the method says 'Try to gracefully degrade if there is no worktree!' — the Option-returning workdir() exists precisely for call sites that can operate without a checkout; this _or_fail variant is for code that fundamentally needs a working tree (index, status, writing files).

Source

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

    /// 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 2497b8007a)

Solutions

  1. Open the non-bare working clone instead of the bare repository.
  2. If bare repos must be handled, branch on ctx.workdir()? and restrict to read-only tree queries.
  3. When accepting user-supplied paths, check core.bare in .git/config up front and reject with guidance.

Example fix

// before
let workdir = ctx.workdir_or_fail()?;

// after
match ctx.workdir()? {
    Some(dir) => { /* normal path */ }
    None => anyhow::bail!("bare repository has no worktree; open the working clone instead"),
}
Defensive patterns

Strategy: validation

Validate before calling

if ctx.workdir()?.is_none() {
    anyhow::bail!("this operation needs a worktree; bare repositories are unsupported");
}

Type guard

fn has_worktree(ctx: &Context) -> bool {
    ctx.workdir().ok().flatten().is_some()
}

Prevention

When it happens

Trigger: Creating a but Context for a bare clone (git clone --bare), a .git directory, or a repo with core.bare=true, then invoking any API that internally calls workdir_or_fail — workspace operations, file open/diff, status.

Common situations: Automation pointing at repo.git instead of repo; mirror clones; CI operating on bare checkouts; users selecting the wrong folder in a picker.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/0f2b5fc6b7594131. Report an issue: GitHub.