gitbutlerapp/gitbutler · error

Cannot unapply non-existing branch '{branch}'

Error message

Cannot unapply non-existing branch '{branch}'

What it means

unapply looks the branch up both in git (try_find_validated_ref) and in the workspace projection (find_segment_and_stack_by_refname). This error fires when both miss: the branch neither exists as a git reference nor as a segment in the workspace, so there is nothing to unapply and the name is simply wrong or stale.

Source

Thrown at crates/but-workspace/src/branch/unapply.rs:238

            );
        }

        if let Some(workspace_ref_name) = workspace_ref_name.as_ref()
            && workspace_ref_name.as_ref() == branch
        {
            return unapply_workspace_reference(
                ws,
                repo,
                meta,
                workspace_ref_name.as_ref(),
                workspace_disposition,
            );
        }

        let branch_in_ws = ws.find_segment_and_stack_by_refname(branch);
        if branch_in_ws.is_none() {
            if branch_ref.is_none() {
                bail!(
                    "Cannot unapply non-existing branch '{branch}'",
                    branch = branch.shorten()
                );
            }
            // The branch exists in Git, but does not in the workspace: Nothing to do.
            return Ok(Outcome::new(Cow::Borrowed(workspace)));
        }
        let branch_stack_was_entrypoint = branch_in_ws
            .is_some_and(|(stack, _)| stack.segments.iter().any(|segment| segment.is_entrypoint));
        let workspace_tip_was_entrypoint = ws.is_entrypoint();

        let Some(workspace_ref_name) = workspace_ref_name else {
            // This is an ad-hoc workspace by merit of being unnamed.
            bail!("Cannot unapply a branch from an ad-hoc detached workspace");
        };
        let mut ws_md = meta.workspace(workspace_ref_name.as_ref())?;
        if ws.kind.has_managed_ref() || ws.has_metadata() {
            ws.reconcile_metadata(&mut ws_md)?;

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Refresh the branch list (re-traverse workspace + repo refs) and only offer branches that still exist.
  2. Treat this case as a no-op in idempotent callers instead of surfacing an error.
  3. Verify the exact spelling and full ref name (refs/heads/...) before calling.

Example fix

// before
unapply(repo, meta, &ws, branch, opts)?;

// after
if repo.try_find_reference(branch)?.is_none()
    && ws.find_segment_and_stack_by_refname(branch).is_none()
{
    return Ok(Outcome::new(Cow::Borrowed(&ws))); // nothing to unapply
}
unapply(repo, meta, &ws, branch, opts)?;
Defensive patterns

Strategy: validation

Validate before calling

if repo.try_find_reference(branch)?.is_none()
    && ws.find_segment_and_stack_by_refname(branch).is_none()
{
    // nothing to unapply: treat as idempotent no-op
    return Ok(Outcome::new(Cow::Borrowed(&ws)));
}

Type guard

fn branch_exists_anywhere(ws: &but_graph::Workspace, repo: &gix::Repository, branch: &FullNameRef) -> bool {
    repo.try_find_reference(branch).ok().flatten().is_some()
        || ws.find_segment_and_stack_by_refname(branch).is_some()
}

Try / catch

match unapply(repo, meta, &ws, branch, opts) {
    Err(err) if err.to_string().contains("non-existing branch") => {
        Ok(Outcome::new(Cow::Borrowed(&ws))) // idempotent no-op
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling unapply with a branch name that has no git ref and no workspace segment — typo, already-deleted branch, or a name that was never applied.

Common situations: Stale UI state after another client deleted the branch; scripts replaying an old branch list; short-name/full-name mismatches.

Related errors


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