gitbutlerapp/gitbutler · error

GitButler project data does not exist at

Error message

GitButler project data does not exist at '{}'

What it means

repo-installer dump locates the GitButler project data directory via repo.gitbutler_storage_path() and requires it to exist as a directory. If the path doesn't exist (or isn't a directory) the dump cannot proceed, so it fails with this ensure! message including the path.

Solutions

  1. Open the repository in GitButler first so project data is created, then re-run the dump.
  2. Verify the printed path exists: check `.git/gitbutler/` inside the repo.
  3. Restore the deleted storage directory from backup or re-add the project to regenerate it.

Example fix

// before
$ git clone x && but-debug dump repo-installer   # no GitButler data yet
// after
$ gitbutler add-project ./x                      # creates project data
$ but-debug dump repo-installer
Defensive patterns

Strategy: validation

Validate before calling

if [ ! -d .git/gitbutler ]; then echo 'No GitButler project data; open the project in GitButler first'; exit 1; fi

Type guard

fn has_project_data(repo: &gix::Repository) -> bool {
    repo.gitbutler_storage_path().map(|p| p.is_dir()).unwrap_or(false)
}

Prevention

When it happens

Trigger: Running `but-debug dump repo-installer` in a repository that has never been opened/managed by GitButler, so no .git/gitbutler (project storage) directory exists.

Common situations: Fresh clones dumped before ever opening the project in GitButler; storage directory deleted manually; running against a repo from a different machine's layout.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/7f67c7aef240311c. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-debug/src/command/dump/repo_installer.rs:47

    let repo = setup::repo_from_args(args).with_context(|| {
        format!(
            "Could not discover Git repository at '{}'",
            current_dir.display()
        )
    })?;
    let repo = gix::open_opts(repo.git_dir().canonicalize()?, repo.open_options().clone())?;
    let workdir = repo
        .workdir()
        .context("Repository installers require a non-bare repository")?;
    ensure!(
        repo.git_dir() == repo.common_dir(),
        "Repository installers require the main worktree"
    );

    let project_data_dir = repo
        .gitbutler_storage_path()
        .context("Could not locate GitButler project data")?;
    ensure!(
        project_data_dir.is_dir(),
        "GitButler project data does not exist at '{}'",
        project_data_dir.display()
    );

    let base = archive_base_name(&repo)?;
    let archive_root = format!("{base}-repo-installer");
    let output_path = match &installer_args.archive.output {
        Some(path) => current_dir.join(path),
        None => default_output_path(&repo, "repo-installer")?,
    };
    let output_path = OutputPath::new(output_path, current_dir);
    let archive_lock = acquire_archive_lock(&output_path.path, Some(workdir.to_owned()))?;
    let output_path = output_path.with_lock_path(archive_lock.lock_path().to_owned());

    let _repo_guard =
        but_core::sync::exclusive_repo_access(repo.git_dir(), Some(&project_data_dir));
    let clone_remote = clone_remote(&repo, workdir)?;

View on GitHub (pinned to 58e5313667)