gitbutlerapp/gitbutler · error

Cannot apply non-existing branch

Error message

Cannot apply non-existing branch '{branch}'

What it means

`Workspace::apply` cannot apply a branch that does not exist as a reference. If no branch ref was resolved and the incoming branch is not a remote-tracking branch without a local tracking branch (a case that can be materialized), the library bails. This prevents creating phantom stacks from a typo or deleted branch.

Solutions

  1. Verify the branch exists: `git rev-parse --verify refs/heads/<name>` before applying
  2. Fetch the remote if the branch only exists remotely (`git fetch origin <name>`) so a local tracking branch can be created
  3. Correct the branch name in the calling code/script

Example fix

// before
ws.apply(meta, "feautre-x", ...)?;
// after
if repo.find_reference(&format!("refs/heads/feautre-x")).is_err() {
    eprintln!("branch feautre-x does not exist locally");
    return;
}
ws.apply(meta, "feature-x", ...)?;
Defensive patterns

Strategy: validation

Validate before calling

if repo.try_find_reference(&format!("refs/heads/{name}")).is_err()
    && repo.try_find_reference(&format!("refs/remotes/*/{name}")).is_err() {
    return Err(format!("branch {name} does not exist locally or remotely"));
}

Type guard

fn branch_exists(repo: &gix::Repository, name: &str) -> bool {
    repo.try_find_reference(format!("refs/heads/{name}")).map(|r| r.is_ok()).unwrap_or(false)
}

Try / catch

match apply(...) {
    Err(e) if e.to_string().contains("Cannot apply non-existing branch") => /* fetch or correct name */,
    Err(e) => return Err(e.into()),
    Ok(r) => r,
}

Prevention

When it happens

Trigger: Calling apply with a branch name that is neither a local ref nor derivable from remote-tracking refs — e.g. the branch was deleted, was never fetched, or the name is misspelled.

Common situations: Typo in branch name in a script; branch deleted on the remote and locally pruned; stale automation referencing renamed branches; applying before `git fetch` brought the remote branch in.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at crates/but-workspace/src/branch/apply.rs:582

        set_head_to_reference(
            repo,
            new_head_id,
            // Point HEAD at the workspace ref whenever it isn't already there (covers creating the
            // ref and switching off a directly-checked-out branch).
            (!head_on_workspace_ref).then_some(workspace_ref_name_to_update.as_ref()),
        )?;
        return Ok(Outcome {
            workspace: graph.into_workspace()?,
            status: OutcomeStatus::Applied,
            workspace_ref_created: needs_ws_ref_creation,
            workspace_merge: None,
            conflicting_stacks: Vec::new(),
            applied_branches,
        });
    }
    // We will want to merge, but be sure the branch exists, can't apply non-existing.
    if branch_ref.is_none() && !incoming_branch_is_remote_tracking_without_local_tracking {
        bail!(
            "Cannot apply non-existing branch '{branch}'",
            branch = branch.shorten()
        );
    }

    let existing_stacks_superseded_by_branch =
        find_superseded_stacks(branch.as_ref(), &ws, &mut ws_md);
    // At this point, the workspace-metadata already knows the new branch(es), but the workspace itself
    // doesn't see one or more of to-be-applied branches (to become stacks).
    // These are, however, part of the graph by now, and we want to try to create a workspace
    // merge.
    let mut in_memory_repo = repo.clone().for_tree_diffing()?.with_object_memory();
    let mut merge_result = WorkspaceCommit::from_new_merge_with_metadata(
        filter_superseded_metadata_stacks(
            ws_md.stacks.iter(),
            &existing_stacks_superseded_by_branch,
        ),
        filter_superseded_anon_stacks(

View on GitHub (pinned to 58e5313667)