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
- Open the non-bare working clone instead of the bare repository.
- If bare repos must be handled, branch on ctx.workdir()? and restrict to read-only tree queries.
- 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
- Validate the chosen folder is a non-bare clone before creating the Context.
- In folder pickers, filter out *.git directories and bare clones.
- Prefer the Option-returning workdir() wherever the flow can degrade gracefully.
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
- No uncommitted changes found for the selected files
- Could not delete branch '{}'
- repo access failed
- Failed to determine target commit for hunk absorption due to
- Stack has no branches
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/0f2b5fc6b7594131.
Report an issue: GitHub.