gitbutlerapp/gitbutler · warning
project already exists
Error message
project already exists
What it means
AddProjectOutcome::try_project maps the AlreadyExists variant to this error. add_project deduplicates by path: if a Project for that path is already registered, no second one is created and the outcome carries the existing Project. Calling try_project() on that outcome discards the existing project and turns an expected, benign situation into an Err.
Source
Thrown at crates/gitbutler-project/src/project.rs:318
}
impl AddProjectOutcome {
/// This is for tests only.
///
/// Unwraps the `Project` if the project was actually added.
/// Panics if it was not.
pub fn unwrap_project(self) -> Project {
match self {
AddProjectOutcome::Added(p) => p,
_ => panic!("called `AddProjectOutcome::unwrap_project()` on a non-project outcome"),
}
}
/// Try to get the `Project`, returning an error if it was not added.
pub fn try_project(self) -> anyhow::Result<Project> {
match self {
AddProjectOutcome::Added(p) => Ok(p),
AddProjectOutcome::AlreadyExists(_) => Err(anyhow::anyhow!("project already exists")),
AddProjectOutcome::PathNotFound => Err(anyhow::anyhow!("project path not found")),
AddProjectOutcome::NotADirectory => {
Err(anyhow::anyhow!("project path is not a directory"))
}
AddProjectOutcome::BareRepository => {
Err(anyhow::anyhow!("bare repositories are not supported"))
}
AddProjectOutcome::NonMainWorktree => {
Err(anyhow::anyhow!("non-main worktrees are not supported"))
}
AddProjectOutcome::NoWorkdir => Err(anyhow::anyhow!("no workdir found for repository")),
AddProjectOutcome::NoDotGitDirectory => {
Err(anyhow::anyhow!("no .git directory found in repository"))
}
AddProjectOutcome::ReftableRefFormatUnsupported => Err(anyhow::anyhow!(
"unsupported repository reference format: reftable"
)),
AddProjectOutcome::NotAGitRepository(msg) => {View on GitHub (pinned to caf1f223d3)
Solutions
- Match on AddProjectOutcome instead of calling try_project: AlreadyExists(Project) hands you the existing project to reuse
- Before adding, list registered projects and check whether the path is already present
- Make add idempotent in UI/automation: treat AlreadyExists as success
- If the stale record is wrong (e.g. moved path), delete the project first, then add again
Example fix
// before
let project = outcome.try_project()?; // 'project already exists'
// after: handle the outcome enum instead of collapsing it
let project = match outcome {
AddProjectOutcome::Added(p) => p,
AddProjectOutcome::AlreadyExists(existing) => existing, // reuse it
other => return Err(anyhow!("add_project failed: {other}")),
}; Defensive patterns
Strategy: type-guard
Validate before calling
// check registered projects first if you need idempotence without enum handling
let already = controller.list_all_projects()?.iter().any(|p| p.worktree_dir == path);
let outcome = if already { /* reuse existing flow */ } else { add_project(&path, ...) }; Type guard
// the outcome enum itself is the guard — match instead of collapsing via try_project
fn added_or_existing(outcome: AddProjectOutcome) -> anyhow::Result<Project> {
match outcome {
AddProjectOutcome::Added(p) | AddProjectOutcome::AlreadyExists(p) => Ok(p),
other => Err(anyhow!("add_project failed: {other}")),
}
} Try / catch
match add_project(&path, &controller, ...) {
AddProjectOutcome::Added(p) => Ok(p),
AddProjectOutcome::AlreadyExists(existing) => {
tracing::info!("project already registered — reusing it");
Ok(existing)
}
other => Err(anyhow!("{other}")),
} Prevention
- Always match on AddProjectOutcome instead of calling try_project when duplicates are expected
- Make add flows idempotent in the UI (double-submit safe)
- When the stored project is stale (moved path), delete it before re-adding instead of relying on AlreadyExists
When it happens
Trigger: Calling project::add(path) twice with the same path; re-adding a repository after re-install without removing the old record; two components racing to add the same path (first wins); path normalization differences that still resolve to the same stored project.
Common situations: Re-running app onboarding over an existing setup; sync/automation re-adding known projects; UI double-submit of the add-project form.
Related errors
- project path not found
- project path is not a directory
- bare repositories are not supported
- non-main worktrees are not supported
- no workdir found for repository
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/8de8d7072a4dd281.
Report an issue: GitHub.