gitbutlerapp/gitbutler · error
`but merge` requires an active GitButler workspace…
Error message
`but merge` requires an active GitButler workspace (`gitbutler/workspace`). Switch into the workspace and try again.
What it means
The `but merge` command only works inside an active GitButler workspace: the repository must have the managed `gitbutler/workspace` ref, and the loaded workspace kind must report `has_managed_ref()`. The CLI checks this up front (the API enforces it again before mutating anything) and bails with this message when the workspace is absent or unmanaged, because landing a branch onto a target is only defined for GitButler-managed workspaces.
Solutions
- Initialize or re-enter a GitButler workspace first (e.g. `but init` or `but` to enter the TUI and create a workspace), then run `but merge` again.
- Check `git rev-parse gitbutler/workspace` in the repo to confirm the managed ref exists; if missing, the workspace is not active.
- Confirm the working directory: run the command inside the GitButler-managed repository root, not a nested/plain checkout.
- If the workspace was expected to exist, inspect workspace state with `but workspace` / `but status` and re-create it if it was torn down.
Example fix
// before: fails in a plain git repo but merge branch-abc // error: `but merge` requires an active GitButler workspace // after: ensure workspace exists first but init but merge branch-abc
Defensive patterns
Strategy: validation
Validate before calling
// Check for the managed workspace ref before invoking but merge:
const refExists = runGit(['rev-parse', '--verify', 'gitbutler/workspace']).success;
if (!refExists) {
throw new Error('Not in a GitButler workspace; run but init first.');
} Try / catch
try {
runBut(['merge', branchId]);
} catch (e) {
if (e.stderr.includes('requires an active GitButler workspace')) {
runBut(['init']); // create/enter workspace, then retry once
runBut(['merge', branchId]);
} else {
throw e;
}
} Prevention
- Always run but merge from inside a GitButler-managed repository root.
- Initialize the workspace (but init / entering the TUI) before landing commands.
- After workspace teardown (last branch landed, workspace goto), re-create it before further but merge calls.
- Check `git rev-parse gitbutler/workspace` in CI before invoking landing commands.
When it happens
Trigger: Running `but merge <branch-id>` in a plain Git repository with no `gitbutler/workspace` ref, or in a repository where the workspace exists but its `kind` does not have a managed ref (e.g. after workspace teardown, or while in a detached/unmanaged state). The check runs at the top of `handle` after acquiring exclusive worktree access via `ctx.workspace_and_db_with_perm`.
Common situations: Developer runs `but merge` in a repo that has never had `but init`/workspace creation. The workspace was just removed (e.g. after landing the last branch or `but workspace goto` onto a plain branch). The command is executed with `-C <path>` pointing at a non-workspace sub-repo or wrong directory.
Related errors
- `but land` requires an active GitButler workspace…
- a committed transaction always materializes a workspace
- Ambiguous branch ' ', matches multiple items
- Ambiguous branch ' ', matches multiple items
- `but merge` requires an active GitButler workspace…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/91150bededb1162b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but/src/command/legacy/merge/mod.rs:35
pub fn handle(
ctx: &mut Context,
out: &mut OutputChannel,
branch_id: &str,
yes: bool,
no_ff: bool,
whole_stack: bool,
) -> anyhow::Result<()> {
// Resolve the branch identifier and read the target configuration. The managed-workspace guard
// runs here for a friendly message before the prompt; the API enforces it again, along with the
// bottom-segment, conflicted-commit, and triangular-remote guards, before mutating anything.
let (branch_name, base_branch) = {
let mut guard = ctx.exclusive_worktree_access();
{
let (_repo, ws, _db) = ctx.workspace_and_db_with_perm(guard.read_permission())?;
if !ws.kind.has_managed_ref() {
bail!(
"`but merge` requires an active GitButler workspace (`gitbutler/workspace`). \
Switch into the workspace and try again."
);
}
}
let id_map = IdMap::new_from_context(ctx, guard.read_permission())?;
let resolved_ids = id_map.parse_using_context(branch_id, ctx)?;
if resolved_ids.is_empty() {
bail!("Could not find branch: {branch_id}");
}
if resolved_ids.len() > 1 {
bail!("Ambiguous branch '{branch_id}', matches multiple items");
}
let branch_name = match &resolved_ids[0] {
CliId::Branch(branch) => branch.name.clone(),
other => bail!("Expected a branch ID, got {}", other.kind_for_humans()),View on GitHub (pinned to 58e5313667)