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

  1. Recreate or restore the directory at the recorded worktree path (restore from backup, remount the drive, undo the rename).
  2. Remove the project from GitButler's project list and re-add it at its new location.
  3. Check the path exists and is a valid repo before loading: `ls <path>/.git` and `git -C <path> status`.
  4. 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

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


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)