gitbutlerapp/gitbutler · error

ProjectMissing

ProjectMissing

Error message

Could not open repository at '{}'{suffix}

What it means

ProjectController::get_inner with validate=true opens an isolated repo at project.worktree_dir; if open_isolated_repo fails, the error 'Could not open repository at ...' is returned with Code::ProjectMissing. The suffix ' as it does not exist' is appended when the worktree directory is missing entirely, distinguishing a vanished path from an unopenable (present but broken) repository.

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 caf1f223d3)

Solutions

  1. Confirm the path still exists and contains a valid .git; if it moved, re-add the project at the new location and remove the stale entry
  2. Reconnect the drive/mount that hosts the worktree, then retry
  3. On startup, drop project records whose worktree_dir no longer exists so users re-onboard cleanly instead of hitting ProjectMissing mid-session
  4. If the directory exists but still fails, inspect .git integrity (git fsck) — a present-but-broken repo produces the suffix-less variant

Example fix

// before
let project = controller.get_inner(id_or_handle, /* validate */ true)?;

// after: pre-validate stored projects and evict stale ones
let project = controller.get_inner(id_or_handle, false)?;
if !project.worktree_dir.is_dir() {
    controller.delete_project(project.id)?;
    anyhow::bail!("project path {} is gone — re-add the project", project.worktree_dir.display());
}
let project = controller.get_inner(id_or_handle, true)?;
Defensive patterns

Strategy: validation

Validate before calling

// validate the stored path before a validating get
let stored = controller.get_inner(id_or_handle.clone(), /* validate */ false)?;
if !stored.worktree_dir.exists() {
    anyhow::bail!(
        "project path {} no longer exists — remove the project and re-add it",
        stored.worktree_dir.display()
    );
}
let project = controller.get_inner(id_or_handle, true)?;

Type guard

fn project_is_on_disk(project: &Project) -> bool {
    project.worktree_dir.is_dir()
}

Try / catch

match controller.get_inner(id, true) {
    Ok(project) => Ok(project),
    Err(err) if err.to_string().contains("Could not open repository") => {
        // Code::ProjectMissing: drive unmounted / folder moved — prompt re-add
        prompt_user_to_re_add_project()
    }
    Err(err) => Err(err),
}

Prevention

When it happens

Trigger: The project folder was moved, renamed, or deleted after being added; an external/unmounted drive holding the worktree; a corrupted .git making even isolated open fail; a stale project row in the app database pointing at a path from another machine.

Common situations: Users moving repositories in Finder/Explorer after onboarding; projects on network mounts or removable media that are disconnected at startup; synced settings carrying project records to a machine where the path does not exist; .git dir permissions broken.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/6e727a50e86f1fde. Report an issue: GitHub.