gitbutlerapp/gitbutler · error
ProjectMissing
ProjectMissing
Error message
Could not open repository at '{}'{suffix} What it means
ProjectController::get_inner validates that the project's worktree directory still hosts an openable git repository before returning the Project. If repo opening fails, the error includes the worktree path plus a suffix explaining that the directory does not exist when that is the case, and is wrapped with the ProjectMissing error code. Callers get/get_validated surface this when a registered project has disappeared from disk.
Solutions
- Recreate or restore the directory at the recorded worktree path (restore from backup, remount the drive, undo the rename).
- Remove the project from GitButler's project list and re-add it at its new location.
- Check the path exists and is a valid repo before loading: `ls <path>/.git` and `git -C <path> status`.
- If .git is corrupted, re-clone and re-add the project.
Example fix
// before: loading a stale project blindly
let project = controller.get(project_id)?;
// after: validate path first
if !std::path::Path::new(&worktree_dir).join(".git").exists() {
// re-add project at new location or remove it
}
let project = controller.get_validated(project_id)?; Defensive patterns
Strategy: validation
Validate before calling
fn project_path_valid(worktree_dir: &std::path::Path) -> bool {
worktree_dir.exists() && worktree_dir.join(".git").exists()
} Try / catch
match controller.get_validated(project_id) {
Err(e) if e.to_string().starts_with("Could not open repository at") => {
// prompt user to relocate or remove the project
handle_missing_project(project_id)
}
other => other,
} Prevention
- Don't delete or rename project folders while GitButler has them registered.
- Keep repos on always-mounted local disks when possible.
- Remove projects from GitButler before deleting their directories.
- Periodically prune stale project entries.
When it happens
Trigger: Calling get or get_validated for a project whose worktree_dir was deleted/moved, is on an unmounted drive, or whose `.git` is corrupted so git2 cannot open the repository.
Common situations: User deleted or renamed the project folder while GitButler still lists it; external drive or network mount offline; repo moved to a different path; antivirus or sync tools interfering with the .git directory.
Related errors
- non-main worktrees are not supported
- bare repositories are not supported
- `but setup` cannot run from a linked worktree; run it from…
- Cannot currently work in repositories without a worktree
- Cannot currently work in repositories without a worktree
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/6e727a50e86f1fde.
Report an issue: GitHub.
Appendix: source
Thrown at crates/gitbutler-project/src/controller.rs:299
/// Like [`Self::get()`], but will assure the project still exists and is valid by
/// opening a git repository. This should only be done for critical points in time.
pub(crate) fn get_validated(&self, id: ProjectHandleOrLegacyProjectId) -> Result<Project> {
self.get_inner(id, true)
}
fn get_inner(&self, id: ProjectHandleOrLegacyProjectId, validate: bool) -> Result<Project> {
let mut project = self.projects_storage.get(id)?;
// BACKWARD-COMPATIBLE MIGRATION
project.migrate()?;
if validate {
let repo = project.open_isolated_repo();
if repo.is_err() {
let suffix = if !project.worktree_dir.exists() {
" as it does not exist"
} else {
""
};
return Err(anyhow!(
"Could not open repository at '{}'{suffix}",
project.worktree_dir.display()
)
.context(Code::ProjectMissing));
}
}
match project.gb_dir() {
Ok(gb_dir) => {
if !gb_dir.exists()
&& let Err(error) = std::fs::create_dir_all(&gb_dir)
{
tracing::error!(project_id = %project.id, ?error, "failed to create \"{}\" on project get", gb_dir.display());
}
}
Err(error) => {
tracing::error!(project_id = %project.id, ?error, "failed to resolve storage directory on project get");
}View on GitHub (pinned to 58e5313667)